ASP.NET Developer Notes

Ryan Garaygay's ASP.NET notes online
BlogEngine.NET and migration to IIS 7

This blog (and the its parent/main site) is now running on IIS 7 Integrated Mode and would like to share a little of my experience.

There were two major issues with I migrated these blog to IIS 7 [more]

1) Server Error in / Application - Request is not available in this context when I accessed the sites

    *Of course I had customErrors ON so I had to turn it OFF before I was able to see this detail

   Interesting, since the site obviously worked fine in IIS 6 and no changes were made. But after a few google clicks I ran into this written specifically for the error. IIS7 Integrated mode: Request is not available in this context exception in Application_Start from Mike Volodarsky. Implemented the suggestion and that did it.

    Because of IIS 7 architectural changes the request context is not available in the Application Start. And since BlogEngine.NET loads extensions in the Application_Start event and the extension makes extensive use of the request context in path related code (also determining protocol et al) the error occured.

    Based on the article

    "Basically, if you happen to be accessing the request context in Application_Start, you have two choices:

   1. Change your application code to not use the request context (recommended).
   2. Move the application to Classic mode (NOT recommended).
"

    I chose option one otherwise I would have stayed with IIS 6. So what I did is follow his recommended solution and move the Extension loading part of BlogEngine.NET to the BeginRequest but made provisions so that it is only loaded on the first request (and once).

Copying from the article:

void Application_BeginRequest(Object source, EventArgs e)

{

    HttpApplication app = (HttpApplication)source;

    HttpContext context = app.Context;

    // Attempt to peform first request initialization

    FirstRequestInitialization.Initialize(context);

}


class
FirstRequestInitialization

{

    private static bool s_InitializedAlready = false;

    private static Object s_lock = new Object();

    // Initialize only on the first request

    public static void Initialize(HttpContext context)

    {

        if (s_InitializedAlready)

        {

            return;

        }

        lock (s_lock)

        {

            if (s_InitializedAlready)

            {

                return;

            }

            // *** Perform first-request initialization here ... ***

            s_InitializedAlready = true;

        }

    }

}

 

And that's it for the FIRST issue.

 

2) Site worked, but hmmm.. the styles are not being applied. Looking at the code, BlogEngine.NET uses httpHandlers to link to the stylesheets. accessing the link directly in the browser didn't return anything (not found) while doing the same on the old hosting account (IIS 6) returned the style info succesfully. So there must be something wrong with the handlers and modules.

 

Luckily I found this IIS 7.0 Integrated Mode Configuration Changes from BE.NET forum

 

Go ahead and read the article, but the bottomline is : in the web.config move the module and handler configuration sections from the <system.web> to <system.webserver> and a few minor changes. Resulting in (assuming you didn't make changes in this section since you downloaded BlogEngine.NET)

 

<system.webServer>
     <modules>
        <add name="UrlRewrite" type="BlogEngine.Core.Web.HttpModules.UrlRewrite" preCondition="managedHandler" />
        <add name="ReferrerModule" type="BlogEngine.Core.Web.HttpModules.ReferrerModule" preCondition="managedHandler" />
        <add name="CompressionModule" type="BlogEngine.Core.Web.HttpModules.CompressionModule" preCondition="managedHandler" />
        <add name="WwwSubDomainModule" type="BlogEngine.Core.Web.HttpModules.WwwSubDomainModule" preCondition="managedHandler" />
        <!--The CleanPageModule below removes whitespace which makes the page load faster in IE. Enable at own risk -->
        <!--<add name="CleanPageModule" type="BlogEngine.Core.Web.HttpModules.CleanPageModule, BlogEngine.Core"/>-->

        <!--Remove the default ASP.NET modules we don't need-->
        <remove name="Profile" />
        <remove name="AnonymousIdentification" />
    </modules>

    <handlers>
        <add name="FileHandler" verb="*" path="file.axd" type="BlogEngine.Core.Web.HttpHandlers.FileHandler, BlogEngine.Core" />
        <add name="ImageHandler" verb="*" path="image.axd" type="BlogEngine.Core.Web.HttpHandlers.ImageHandler, BlogEngine.Core"/>
        <add name="SyndicationHandler" verb="*" path="syndication.axd" type="BlogEngine.Core.Web.HttpHandlers.SyndicationHandler, BlogEngine.Core"/>
        <add name="SiteMap" verb="*" path="sitemap.axd" type="BlogEngine.Core.Web.HttpHandlers.SiteMap, BlogEngine.Core" />
        <add name="TrackbackHandler" verb="*" path="trackback.axd" type="BlogEngine.Core.Web.HttpHandlers.TrackbackHandler, BlogEngine.Core" />
        <add name="PingbackHandler" verb="*" path="pingback.axd" type="BlogEngine.Core.Web.HttpHandlers.PingbackHandler, BlogEngine.Core" />
        <add name="OpenSearchHandler" verb="*" path="opensearch.axd" type="BlogEngine.Core.Web.HttpHandlers.OpenSearchHandler, BlogEngine.Core" />
        <add name="MetaWeblogHandler" verb="*" path="metaweblog.axd" type="BlogEngine.Core.API.MetaWeblog.MetaWeblogHandler, BlogEngine.Core" />
        <add name="RsdHandler" verb="*" path="rsd.axd" type="BlogEngine.Core.Web.HttpHandlers.RsdHandler, BlogEngine.Core" />
        <add name="CssHandler" verb="*" path="css.axd" type="BlogEngine.Core.Web.HttpHandlers.CssHandler, BlogEngine.Core" />
        <add name="JavaScriptHandler" verb="*" path="js.axd" type="BlogEngine.Core.Web.HttpHandlers.JavaScriptHandler, BlogEngine.Core" />
        <add name="RatingHandler" verb="*" path="rating.axd" type="BlogEngine.Core.Web.HttpHandlers.RatingHandler, BlogEngine.Core" />
        <add name="OpmlHandler" verb="*" path="opml.axd" type="BlogEngine.Core.Web.HttpHandlers.OpmlHandler, BlogEngine.Core" />
        <add name="MonsterHandler" verb="*" path="monster.axd" type="BlogEngine.Core.Web.HttpHandlers.MonsterHandler, BlogEngine.Core" />
        <add name="BlogMLExportHandler" verb="*" path="blogml.axd" type="BlogEngine.Core.Web.HttpHandlers.BlogMLExportHandler, BlogEngine.Core" />
    </handlers>
</system.webServer>

And that did it for me :)

FROM : .NET Developer Notes on BlogEngine.NET and IIS 7 Migration

Posted: Jan 28 2009, 01:32 AM by ryangaraygay | with 4 comment(s)
Filed under: ,
remove malicious script tags from file

Just want to share a "simple" Windows Forms application that I created to automate removal of malicious SCRIPT tags inserted into some web files.

Read full article on .NET Developer Notes on remove malicious script tags from file

WindowsPrincipal.IsInRole doesn't reflect changes until restart

Just an observation sometime ago that if you create a new Windows Role and add a user to it and create a WindowsPrincipal using that user, the IsInRole method doesn't reflect the membership change made until a restart is made.

Read the full article from .NET Developer Notes on WindowsPrincipal.IsInRole doesn't reflect changes until restart 

Posted: Jan 26 2009, 01:04 AM by ryangaraygay | with 1 comment(s)
Filed under:
Address1 vs Address2

I've been working to something related to address validation for some time I figured I should share this tid bit about the Address1 and Address2 in forms (especially online forms)

When asked for personal information it is not uncommon to be prompted for the following:

Name, Address1, Address2, City, State, ZIP

What really is the difference between Address1 and Address2 and is it significant? [more]

NO, Address2 is not asking for a backup of whatever you put in Address1. It not like a "confirm" address field. Nor it is simply a "continuation" of Address1

It depends on the country but generally (e.g. US)

* Address1 is expected to have Street Number, Street Name, or maybe PO Box.

* Address2 is for Apartment, Floor, Suite, Bldg # or more specific information within Address1

And also, if there is no company field Address2 will be a better place to write it on than Address.

Safe to say that Address1 should be general (but enough to pinpoint a geographical location - and obviously not include City, State, ZIP, Country) while other extra information should be in Address2.

Address2 fields in forms are generally (and for usability) shorter and in my opinion should have at least include hints as to what goes to it.

Also, for US ZIP code lookup you might find the following link from USPS helpful : USPS ZIP Code Lookup

Hope this info helps.

FROM: .NET Developer Notes on Address1 vs Address2

caution in dropping a temp table before creating it

Recently I ran into a script instead a stored procedure

IF OBJECT_ID(tempdb..#temp1) DROP TABLE #temp1

Basically, the object of this script is to check if #temp1 (regular temporary table) exists. If so drop it.
However, I think it can have unintended consequences and maybe safer not to include. [more]

Say you have a script that includes the call to the stored procedure (eg. SampleStoredProc)
If the script (let’s call this “caller”) creates a table #temp1 and at the top of SampleStoredProc you have if object_id(tempdb..#temp1) drop table #temp1, what will happen is that the #temp1 table of the “caller” will be dropped.
And the caller might not want that (or won’t expect that the #temp1 table he/she created will be dropped). It is possible that after calling SampleStoredProc the caller would still want to use/access #temp1.
On the other hand if no drop table #temp1 is executed inside SampleStoredProc and a create table #temp1 is made even if the “caller” has a #temp1 already it will not be a problem. The #temp1 of the caller and #temp1 of BehavClusDOM1 will be separately identified.
Since BehavClusDOM1 is a stored procedure it is a scope for temp tables and safe to assume that at the start of the stored procedure no temp tables are present in that scope.
Basically the idea is that BehavClus should not touch whatever is beyond its scope.

So in my opinion the inclusion of this code can cause unexpected behavior to the caller while removing it poses no risk not to mention shortening the code and decreasing complexity and readability. The author of the stored procedure (eg. SampleStoredProc) involving creation of #temp1 should know when it is present and shouldn't worry about clashing with another #temp1 in another session. You can explicitly DROP TABLE #temp1 if you want but only after you have created your own #temp1 so your sure that you'd be dropping the one you created and not that in other scripts.

FROM : .NET Develoer Notes on caution in dropping a temp table before creating it

Posted: Jan 24 2009, 06:34 PM by ryangaraygay | with no comments
Filed under:
temp table (#), global temp tables (##) and @table variables

 

I've been working "full-time" on TSQL scripts for the past month (no with .NET windows/web apps) and mostly on optimization. And I feel that I should share with everyone this article about temp tables and table variables and some of my own notes. Go read the article below then you may come back here. Take careful note of the Conclusion part at the end of the article. [more]

Should I use a #temp table or a @table variable?

Things to generally consider are speed, disk space and cpu utilization, persistence. And here are some short hopefully helpful notes.

1) persistence - if you need the data to persist even after the execution then no doubt you need to use permanent tables.

2) cpu utilization - always review indexes. effect of the use of regular temp, global temp tables, table variables to performance is not as significant as a missing index. Among other things, it is safe to say, always ensure you have a primary key. and also if you will perform queries with ORDER BY then always consider your clustered indexes are correct. you can use estimated or actual execution plans to analyze your queries. I recommend SQL profiler too but correct me if I'm wrong but they are only able to profile permanent tables.

3) speed - first thing, indexes again too (see above). Secondly and very important - Although table variables may seem (and actually common) faster than temp tables, my observation is that if you are dealing with large datasets then temp tables are way way faster than table variables. I could not quantify giving the dataset I'm working on but suffice to say that it took quite a number of folds faster that I cancelled the execution.

4) disk space - temp tables, global temp tables and table variables take up the same space as permanent tables would. But they should be cleared once the procedure/function goes out of scope. The tempdb transaction log is less impacted than with #temp tables; table variable log activity is truncated immediately, while #temp table log activity persists until the log hits a checkpoint, is manually truncated, or when the server restarts

FROM: .NET Developer Notes on temp table (#), global temp tables (##) and @table variables

Posted: Jan 24 2009, 06:33 PM by ryangaraygay | with no comments
Filed under:
Convert Delimited Values to a table with Ordinal Column

 

This is a script to conver a delimited/separated values given a delimiter into a table, via a User Defined Function.

This has saved me a lot of work already including just now so I gfigured this is a good share

My apologies as I could not determine where I based this script from but definitely I got it from someone else rather than created my own. Had a few revisions along the way.

CREATE FUNCTION [dbo].[Split]
(
  @String VARCHAR(200),
  @Delimiter VARCHAR(5)
)
RETURNS @SplittedValues TABLE
(
  Ordinal SMALLINT IDENTITY(1,1) PRIMARY KEY,
  SplitValue VARCHAR(MAX)
)
AS
BEGIN
  DECLARE @SplitLength INT
  WHILE LEN(@String) > 0
  BEGIN
    SELECT @SplitLength =
      (CASE CHARINDEX(@Delimiter,@String)
        WHEN 0 THEN LEN(@String)
        ELSE CHARINDEX(@Delimiter,@String) -1
      END)
    
    INSERT INTO @SplittedValues
      SELECT SUBSTRING(@String,1,@SplitLength)
      SELECT @String =
        (CASE (LEN(@String) - @SplitLength)
          WHEN 0 THEN ''
          ELSE RIGHT(@String, LEN(@String) - @SplitLength - 1)
        END)
  END
  RETURN
END
GO

From : .NET Developer Notes on Convert Delimited Values to a table with Ordinal Column

 

Posted: Jan 24 2009, 06:32 PM by ryangaraygay | with no comments
Filed under:
Performance, Measure and ANTS Profiler

Might need to create a separate page for notes on performance since I've been doing a lot of C# and database tuning lately but having them on this post so far. Here are some of my notes on performance [more]

* Before you optimize, ensure that your results are accurate first before optimizing. I would suggest Test Driven Development or at least some unit testing but that's another story. Just make sure your results are correct first otherwise your optimization is useless.

* Before you optimize, always MEASURE MEASURE MEASURE

* If you can measure without introducing extra code, go with it. Aside from saving time, it will keep your code clean and introduce what could be unnecessary complexity. And for this very reason I just purchase ANTS Profiler 4 from RedGate software. Another alternative is dotNetTrace from JetBrains and although I love Resharper from the same company I prefer ANTS profiler. I said prefer because as I haven't explored dotNetTrace that much, i would say it is really preference, UI/usability and being able to view the timings embedded in a window which shows the source code. Also like the call graph, drill down on significant methods in terms of time spent on it. I got a quote for a no support/update version of the software when I emailed RedGate about their pricing which is admittedly very high for a personal purchase when you are earning from a 3rd world country. So will be receiving fixes but not major upgrades (so as they say but haven't dug deep - besides the version looks pretty good and turns out to be very useful for me already). It really sucks to try to optimize something only to find out that it is not the bottleneck

* If your application involves database access and you're slow then more often than not your database is not tuned. And SQL Profiler and Database Tuning Advisor is a very good start. You can apply the recommendations or you can just evaluate them and make your own adjustments. In my experience however the recommended changes does make a lot of performance improvement. You think you know enough about indexes and database design? You might be surprised how much performance you can gain from these tools.

Again measure, measure, measure but if you can only identify some specific parts then data access seems like a good start.

* Then look into you application logic. Even if your code is optimized but your algorithm/logic is wrong, it will still turn out bad

* Also know about database/table statistics, indexed views and partition. If you can take advantage of partitions and involving considerable data access the improvement is quite impressive.

* <string>.SubString(...) does some considerable lifting so if you want to check if the first two chars in a string is equal to some other string then you should consider using <string>.StartsWith instead or avoid the SubString if you can

* Hashtable is faster than SortedDictionary, SortedList or List. I know I should provide stats for this (have a URL somewhere and will update this soon)

* When using nullable types, use <variable>.HasValue as much as possible than comparing using != null. Or even "!<var>.HasValue" vs. "== null". But avoid negation if you have to

Finally this list will grow soon hopefully and if feel like you disagree please feel free to comment and have other benefit from your thoughts too :)

Taken from : .NET Developer Notes on Performance, Measure and ANTS Profiler

Ancestor and Descendant IDs/info list using Common Table Expressions

Needed some TSQL code again to retrieve descendant and ancestor entries in a self-referencing table. I've done this a couple of times already and although I can write it from the top of my head, sometimes you just want to make life easier and have a script you can just modify a bit to fit the new requirement.

So what I usually use for recursions in SQL Server 2005 are Common Table Expressions (the "WITH" keyword). This is only available in SQL 2005 and very easy/efficient for recursive.

This is definitely in BOL and articles all over nevertheless here's my basic script to get "Descendants and Self" and "Ancestors and Self" information. In this case I only involved the ID, ParentID, and Sequence but you may add more columns (ID and ParentID are required to work). Also you might want to just retrieve the ID and just perform a JOIN afterwards.

Please read full article from .NET Developer Notes on Ancestor and Descendant IDs/info using Common Table Expressions

Posted: Jul 12 2008, 05:24 AM by ryangaraygay | with no comments
Filed under:
Sys.ArgumentException: Value must not be null for Controls and Behaviors

I was going thru some pages for my current project today when I ran into the said error "Sys.ArgumentException: Value must not be null for Controls and Behaviors". It was the first time I've encountered it and since it was working the last time I browsed it I didn't have a clue what was causing it so had to dig around. [more]

I have tested the page though I have to admit that not thoroughly (yeah I know, don't check in not well tested code) and there was no automated UI tests for it, took me sometime to stop the cause. I had to consider what applications I installed on my machine recently or other changes.

After some digging it turns out that it is related to a modalPopupExtender (part of AJAXControlToolkit) in the page.

Moving on, the extender's TargetControlID was set to let's say "linkAddItem" control.

Now, the catch is that recently I added an inline condition (ok, not really sure what is the right term for this but something like the one below):

<% if(MyCondition) { %>

<asp:LinkButton ID="linkAddItem" (definition here.... plus some other text) 

<% } %> 

So as you might have guessed, the page was looking for "linkAddItem" but in case MyCondition is true, it would not be rendered thus causing the error. I had read somewhere that if you have the TargetControl's (eg. linkAddItem) Visible attribute equals to "false", the AJAX control toolkit code would be able to detect with no problems. But not this one. The "Valu" mentioned in the error is likely the TargetControlID or at least related to it. You could verify by debugging the client script if this wouldn't solve the problem but fortunately enough not to go that far.

To cut this short story even shorter, my work-around was to instead have that block wrapped inside a panel (<asp:Panel...) and on Page PreRender, set the Panel.Visible = MyCondition. To simplify you could set just the control (eg. linkAddItem) Visibility but since there are other controls in that block, in my case the panel would be good.

I believe you can also set Visible='<%= MyCondition %>' of the panel in the ASPX page rather than at runtime/code for as long as you have the Page databound. : this.DataBind(); (but be careful, this is recursive and would rebind all other controls in your page you have bound previously).

Next time you run into this error, it is likely that one of the possible suspect is control visibility.

Cross post from .NET Developer Notes

More Posts Next page »