ASP.NET
ASP.NET related posts.
Visual Studio 2008 SP1 and .NET 3.5 SP1 RTM

imageVisual Studio 2008 SP1 (Service Pack 1) is ready for download. 

 

Click below for the links:

VS2008 SP1 EXE Installer:

http://www.microsoft.com/downloads/details.aspx?FamilyId=FBEE1648-7106-44A7-9649-6D9F6D58056E&displaylang=en

or

VS2008 SP1 ISO Installer:

http://www.microsoft.com/downloads/details.aspx?FamilyId=27673C47-B3B5-4C67-BD99-84E525B5CE61&displaylang=en

 

Happy updating!

-Brian Chavez

Add Comment Filed Under [ ASP.NET C# ]
Understanding ScriptResource and WebResource in ASP.NET

Here are some common questions about ASP.NET and web resources:

  • What is a web resource?
  • How do I get my embedded scripts to be delivered by ScriptResource.axd handler?
  • How do I get my embedded scripts to be delivered by WebResource.axd handler?
  • What is the difference between ScriptResource.axd and WebResource.axd?

First, let's tackle the first question.  What is a web resource and why would you use such a thing?

Web Resources

A web resource is a file embedded in an assembly.  This file can either be a JavaScript file or a BMP, or any other emendable type of resource in an assembly.  Just take a look at System.Web and all the embedded resources that are defined:

image

You'll notice there are both, Images and Scripts.  There's even some html!  So, web resources (at an assembly level) can be composed of just about anything you want.

How do you define Web Resources?

Meet the [WebResource] attribute.  You define web resources by using the WebResource attribute.  The WebResourceAttribute acts as an access marker to allow resource handlers to find your resources.  The first parameter to WebResource is the name of the web resource, the second parameter is the ContentType.

[WebResource(
  webResourceName
    Type: System.String
    The name of the of Web resource.
,
  contentType
    Type: System.String
    The type of resource, such as "image/gif" or "text/javascript".
)]

image Once you have your [WebResource] defined in your assembly, the next step is to mark the file you want embedded as an "Embedded Resource" in Visual Studio.

 

 

 

Working with Assembly Resources

There are two basic ways to getting at your assembly resources loaded on your ASP.NET web page.  ScriptResource.axd and WebResource.axd.

Using WebResource.axd

Generally, you'll want to use WebResource.axd when you are dealing with binary resources.  Things like emendable images or other types of media.  You can use WebResource for serving out JavaScript files but there is a better alternative.  However, if you're stuck in ASP.NET 2.0 land with out Microsoft AJAX, then WebResource.axd is your only option to serve out your embedded assembly resources.  To make your assembly resources available on your ASP.NET page, simply use:

  104  //Uses WebResource.axd

  105  this.Page.ClientScript.RegisterClientScriptResource(

  106     typeof(SwfObject), "ProjectBase.Web.Scripts.swfobject.js" );

  107 

  108  string urlToFunnyWebResourceUrl =

  109     this.Page.ClientScript.GetWebResourceUrl(

  110     typeof(SwfObject), "ProjectBase.Web.Images.Header.gif" );

urlToFunnyWebResourceUrl is the the actual absolute path to your webresource.  So you could potentially use it to link to an image or script.  ClientScript.Register* are generally reserved for loading JavaScript.  It's pretty straight forward, pass in the typeof(Control) that's requesting the resource, and the full name to the assembly resource.  The result of these calls will generate URLs to WebResource.axd.

Using ScriptResource.axd

As I mentioned earlier, there is a better alternative for loading your JavaScript assets if you're working with ASP.NET AJAX.  Using ScriptResource.axd handler actually has some interesting features.  Some features include:

  • Automatically GZip/Compressing your scripts over HTTP for delivery.
  • Dynamically resolving Release/Debug scripts based on build parameters.  This is useful, if you keep two types of the same script: one for debug, and one packed for release.
  • Can be used for Non-MsAJAX Framework script assets such as jQuery.

The ScriptManager object is how we can get our embedded JavaScript into our page using ScriptResource.axd:

  112  //Uses ScriptManager.axd

  113  ScriptManager.RegisterClientScriptResource(

  114     this, typeof(SwfObject), "ProjectBase.Web.Scripts.swfobject.js" );

The calling semantics are pretty much the same as the previous calls to WebResource.axd, the only difference is that we are passing in this instance of the control that wants to register the script.  The effect of calling this method results in scripts being loaded from ScriptResource.axd.

That's it!  Happy coding!  I'll probably add some more tips on this post if I come across any.

Brian Chavez

The ParseChildren PersistChildren and PersistenceMode.InnerProperty

After a while of non-web control development, ParseChildren and PersistChildren attributes are important attributes to remember when trying to get the desired results your looking for in the Visual Studio designer.

So, this post should clear up (and serve as a reminder for me) how and why these attributes are important.  Let's explore what these two attributes are used for.  Let's start with ParseChildren.

The [ParseChildrenAttribute]

The ParseChildren Attribute is probably, the most important attribute you should pay attention to when developing web controls.  It's actually used by the ASP.NET Parser and ControlBuilder object to figure out how to parse the ASP.NET code you write.  Visual Studio also uses this attribute to figure out what valid sub-controls and components are allowed within the contents of a server control.

Let's say, I want to create an AggregateFeeds control that displays an aggregate list of RSS feeds.

A Basic and Boring Control Syntax

image

You'll notice that the RssResource is the only available option that is allowed as a child from the AggregateFeeds control.  Here's the code behind the AggregateFeeds control:

  113     [

  114     ParseChildren(

  115         typeof(RssResource),

  116         DefaultProperty = "Feeds",

  117         ChildrenAsProperties = true

  118         )

  119     ]

  120     public class AggregateFeeds : Control

  121     {

  122         public AggregateFeeds()

  123         {

  124             this.Feeds = new RssFeedCollection();

  125         }

  126         public RssFeedCollection Feeds

  127         {

  128             get;

  129             private set;

  130         }

  131         protected override void Render(HtmlTextWriter writer)

  132         {

  133             this.Feeds

  134                 .ForEach( rssRes => writer.Write( rssRes.Url ) );

  135         }

  136     }

  137 

  138     public class RssFeedCollection : List<RssResource>

  139     {

  140 

  141     }

  142 

  143     public class RssResource

  144     {

  145         public string Url { get; set; }

  146     }

The ParseChildren attribute on AggregateFeeds tells the ASP.NET, that any children within the AggregateFeeds control should be typeof(RssResource)ChildrenAsProperties=true let's ASP.NET know that it should STOP parsing server controls with "runat=server", and switch to instantiating objects into the properties of the ArggregateFeeds control.  DefaultProperty says, that the results of the parsed objects should go into the default property Feeds.

Syntax Goodness With InnerProperty

The previous example was great, it's simple and get's the job done.  But let's say, the requirements have changed, our control is growing, and we need to allow more customization, and extensibility for the consumers of our AggregateFeeds control.

Let's clean up the markup and allow our developers to create markup like this:

image

To get this type of syntactical behavior, check out the code below:

  113     [

  114     ParseChildren(

  115         ChildrenAsProperties = true

  116         )

  117     ]

  118     public class AggregateFeeds : Control

  119     {

  120         public AggregateFeeds()

  121         {

  122             this.Feeds = new RssFeedCollection();

  123         }

  124 

  125         [PersistenceMode(PersistenceMode.InnerProperty)]

  126         public RssFeedCollection Feeds

  127         {

  128             get;

  129             private set;

  130         }

  131         [PersistenceMode(PersistenceMode.InnerProperty)]

  132         public AggregateSettings Settings

  133         {

  134             get;

  135             private set;

  136         }

  137         protected override void Render(HtmlTextWriter writer)

  138         {

  139             this.Feeds

  140                 .ForEach( rssRes => writer.Write( rssRes.Url ) );

  141         }

  142 

  143     }

  144 

  145     public class AggregateSettings

  146     {

  147         public int TimeOut { get; set; }

  148         public bool CacheResults { get; set; }

  149     }

  150 

  151     public class RssFeedCollection : List<RssResource>

  152     {

  153 

  154     }

  155 

  156     public class RssResource

  157     {

  158         public string Url { get; set; }

  159     }

Notice, we've removed DefaultProperty and typeof(RssResource) from ParseChildren attribute.  We're no longer working with a simple control that has simple children objects that need to be parsed, we're now working with a complex control with more than one property that we're setting in the markup, so we've removed the "default" stuff.  The syntactical magic happens with PersitanceMode attribute on the properties.  PersistanceMode.InnerProperty allows us to specify our cool <Feeds> and <Settings> tags.  How does Visual Studio know what members are available?  It does so by Reflection.

Get fancy, more than one child type

Also, I want to point out, suppose, we want to support multiple types of Feed objects.  We could use an enum in RssResource, or we could use inheritance to achieve the following:

image

All we would have to do is simply mark RssResource as an abstract class. Then, subclass for each type.

  156     public abstract class RssResource

  157     {

  158         public string Url { get; set; }

  159     }

  160     public class MediaRss : RssResource

  161     {

  162 

  163     }

  164     public class ITunesRss : RssResource

  165     {

  166 

  167     }

Again, I'm just showing that it's possible, but following my mantra of "less code, less maintenance," I'd use an enum to describe the type of rss feed on RssResource.

Where is [PersistChildren]?

Nowhere!  Is PersistChildren attribute needed?  No, it's not a required attribute to create your custom control.  The PersistChildrenAttribute only provides designer support for your control with Visual Studio and has no "processing" affect in ASP.NET, but remember ParseChildren does.

I'm a image  source-view only guy.  I really don't remember the last time I've used the Visual Studio "Design View", it's a waste, crashes all the time, so I've pretty much given up on it.  Besides, "Design View" is for n00bs anyway.  Just kidding!  If you plan on using the Design View, then you'll probably need your PersistChildren attribute...

In general, PersistChildren and ParseChildren are exclusive complementary attributes to describe the same semantic operation.  The rule of thumb goes:

If ParseChildren(true), then PersistChildren(false)

If ParseChildren(false), then PersistChildren(true).

Following the PersistChildren guideline above should keep your code out of trouble.  But again, I wouldn't use PersistChildren only until you actually need it.  Less code, less maintenance.

Here's a nice list of attributes you should consider when writing your custom controls:

http://wdevs.blogspot.com/2007/10/attributes-to-consider-applying-when.html

Hope that helps! Happy coding!

Brian Chavez

NHibernate - null id in entry (don't flush the Session after an exception occurs)

imageI ran into this issue today when trying to persist one of my objects.  The cause of the problem was interesting.  I was trying to save an object when a property/columns in the table had a unique constraint.  As a result, the object that I was trying to persist would not persist simply because the object's property it failed to meet the unique constraint.

As a result, a call to Save() on the object failed and the ID on the object I was trying to save was not set, but NHibernate still processed the object and associated it with its persistence mechanism leaving it in a "semi-persistent" state with the NHibernate persistence manager (ie: NHibernate now knows about the object you tried to save and it SHOULD have fully evicted the object from its persistence manager because the save failed, but it didn't).

When an HTTP request finishes on my ASP.NET application, I flush and close all NHibernate session objects at the time the request is done.  And as a result, when the HTTP request finished, NHibernate attempted to flush the jacked up "semi-persistent" object (an object who's ID was null) and ultimately generating the error above.

So, the solution that I implemented was to wrap the Save() in a try{} catch{} statement, and if the save failed, immediately close and shutdown the session, handle the error/exception.  Then, check if Session.IsOpen when the HTTP request finishes.

Hope that helps, confused0081.gif

Brian Chavez

Slink Framework - Strongly Typed URLs for ASP.NET

 image926

image_thumb15_thumb45

I decided it was time to solve a very annoying and time consuming code maintenance/quality problem when working with ASP.NET and Visual Studio, URL verification.  If you're like me, you've probably had your fair share of HTTP 404s and ASP.NET maintenance troubles whenever you renamed a file in your web project and broken URLs in the code-behind pages that contain scattered uses of Response.Redirect() similar to the following:

protected void Page_Load(object sender, EventArgs e)

{

    if ( User.IsInRole( "admin" ) )

    {

        Response.Redirect( "~/Page2.aspx" );

    }

    if( User.IsInRole( "employee" ) )

    {

        Response.Redirect( "~/EmployeePages/ViewCustomers.aspx" );

    }

    if( User.IsInRole("customer") )

    {

        Response.Redirect( "~/CustomerPages/ViewCatalog.aspx" );

    }

}

The site validation in Visual Studio somewhat is limited in its ability to validate URLs.  Visual Studio validates URLs in the HTML markup view, but doesn't validate your URLs in code-behind pages.  That's a bummer, because the code above is somewhat common in projects.  Invalid URLs that exist in your code-behind pages are hard to debug and locate... you usually don't know when you have an invalid URL lurking in your code-behind until you hit the page with your browser.  Most modern refractoring tools today do a good job refactoring code for renamed files; however, since most refactoring tools are searching for strings when renaming an ASPX file, there is a potential for error.  There have been many times when refactoring didn't help me and only made the problem worse by selecting the "search string literals" option.  Refactorability degrades when you start dealing with different media types in your markup and code-behind pages, such as Images, SWF, CSS, and JavaScript URLs.  Media types like these go unchecked, try refactoring those in your pages!mad0259.gif  Personally, I'd love it if there was some kind of strongly typed URL framework.  Fortunately, there has been some work in this area by Fabrice Marguerie and his open source project PageMethods.  In summary, PageMethods was too strict, and didn't work well for my purposes.  I simply wanted a light-weight and fast URL framework to provide links to pages and media objects that I could use in code-behind pages and HTML markup.  I also wanted to know at compile time the validity of all the URLs in my project.  So, I decided to tackle the problem myself with a small project I created called (Strong Link), aka Slink.

Now, let's revisit the same maintainability problem above using Slink with strongly typed URLs:

protected void Page_Load( object sender, EventArgs e )

{

    if( User.IsInRole( "admin" ) )

    {

        Response.Redirect( Slinks.Page2.TidleUrl );

    }

    if( User.IsInRole( "employee" ) )

    {

        Response.Redirect( Slinks.EmployeePages.ViewCustomers.TildeUrl );

    }

    if( User.IsInRole( "customer" ) )

    {

        Response.Redirect( Slinks.CustomerPages.ViewCatalog.TildeUrl );

    }       

}

With Slink, not only do you get cleaner code, you get compile time checking for code-behind pages! You can also use type safe links in HTML markup:

<h4>Customer Pages</h4>

 

<!-- The old way, using relative path -->

<img src="~/Images/CustomerImage.jpg" alt="not strongly typed image" />

 

 

<!-- The new Slink type safe way, using img HTML tag -->

<img src='<%# Slinks.Images.JPG.CustomerImage.TildeUrl %>' alt="strongly typed url"

     runat="server" />

 

<!-- The new Slink type safe way, using a web control -->

<asp:Image ID="imgControl" runat="server"

           ImageUrl='<%# Slinks.Images.JPG.CustomerImage.TildeUrl %>' />

Yeah! And the list goes on:

  • Better Maintainable Code
  • Better Cleaner Code
  • Better Readable Code
  • Better Refactorable Code
  • Better Quality Code
  • Support for media types other than ASPX pages
  • Fast code generation
  • Non-intrusive overhead (no need to call any setup methods or expensive runtime checking)
  • Use as-you-go integration (doesn't require any rewrites of your code to start using Slink)
  • XML configuration based
  • Intellisense for any of your files and media objects!

Now that's what I'm talking about. So how do you get your hands on all this Slink ASP.NET goodness?  Keep reading...

 

Getting Started with Slink

There are two basic ways to use Slink:

  • You can use Visual Studio and an accompanying CR_Slink Plug-In (via DXCore) to automatically generate a type safe file in your projects App_Code directory.

OR

  • You can use Slink.exe in a build task to generate a strongly typed safe file in your App_Code directory.

Details about how to setup each method is discussed later.  First, there's some XML configuration you'll need to perform to tell Slink what to generate.  Here is a sample configuration that you place in your Web.config:

<!-- Web.config -->

<configuration>

  <configSections>

       <section name="Slink" type="Slink.Core.SlinkConfigSection, Slink.Core"/>

  </configSections>

  <Slink>

     <GlobalSettings EngineEnabled="True" RootNamespace="Slinks"/>

     <NamespaceRules>

        <add key="aspxFiles" Extension="*.aspx" UseFolderNamespace="True"/>

        <add key="jpgFiles" Extension="*.jpg" NamespaceOverride="Images.JPG"/>

        <add key="pngFiles" Extension="*.png" NamespaceOverride="Images.PNG"/>

     </NamespaceRules>

  </Slink>

  <!-- Other configuration settings go here -->

</configuration>

Below is a brief explanation of the XML configuration settings...

<section name="Slink" type="Slink.Core.SlinkConfigSection, Slink.Core"/>

  • This section handler needs to be added to the <configSections>.  The <section> tag defines the XML node that is to be handled by the SlinkConfigSection on behalf of the .NET configuration framework.

<Slink>

          <GlobalSettings EngineEnabled="True" RootNamespace="Slinks"/>

  • The <GlobalSettings> node has two attributes EngineEnabled and RootNamespace.
    • EngineEnabled - Boolean - This is a project level setting. You may want to disable type safe link code generation at the project level if you are working with multiple Web Projects.  Setting EngineEnabled="False" disables code-generation at the web-project level.
    • RootNamespace - String - Allows you to specify the Namespace for all type safe links.

image_thumb115 

<NamespaceRules>

    <add key="aspxFiles" Extension="*.aspx" UseFolderNamespace="True"/>

    <add key="jpgFiles" Extension="*.jpg" NamespaceOverride="Images.JPG"/>

    <add key="pngFiles" Extension="*.png" NamespaceOverride="Images.PNG"/>

</NamespaceRules>

  • <NamespaceRules> are at the core of Slink.  Namespace rules dictate how type safe code is generated by the Slink Engine.  Namespace rules allow you to define what type of files get type safety.
    • Extension - String - If you wish to have type safe code generated for all ASPX pages, add a namespace rule with the Extension attribute set to "*.aspx". Including the * (asterisk) is necessary.
    • UseFolderNamespace - Boolean - Uses the file path to generate the sub-namespaces below the root namespace.
    • NamespaceOverride - String - Overrides the UseFolderNamespace attribute and allows you to define your own custom path.  Your custom namespace override is appended to RootNamespace. See the example below for JPG and PNG namespace overrides:

image_thumb15_thumb35

NOTE: If you have multiple files with the same name but different extension, you'll want to override namespaces to avoid type collision.

Now that we have XML configuraiton out of the way, I'll walk you through on how to install Slink on your machine.

 

Using Visual Studio Slink Plug-In

image_thumb285

Installing VS.NET Plug-In

  1. Install the DXCore (free) extensibility framework for Visual Studio from Developer Express here.
  2. Download the Slink binaries Slink_bin.zip.
  3. Copy the contents of Slink_bin.zip into your DXCore Plug-In directory
    • Ex: C:\Program Files\Developer Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins
    • Note: All contents of the Slink_bin.zip must be extracted into the plugins directory.
  4. Make sure your XML config section is defined in your Web.config, and start coding away!

 

Using Slink.exe

image_thumb275

Now, if you're already using the Visual Studio Plug-In, there's no need to use the Slink.exe.   But for those of you who don't have Visual Studio, or are using Visual Studio Express, using Slink.exe is the way to go.

Installing Slink.exe

  1. Download the Slink binaries Slink_bin.zip.
  2. Extract the contents of to the directory of your choice
    • Ex: C:\Tools
  3. Run the following from the command line:
    • C:\Tools> slink.exe /webproject:<PathToWebProject>
    • Replace <PathToWebProject> with the full path to your project.
  4. Be sure to modify your Web.config and your Namespace Rules are set.  Otherwise, the Slink won't know what to do.

TIP: Unfortunately, Web Projects in Visual Studio are handled differently than ordinary projects.  With web projects, you can't specify any "Pre-Build" event tasks.  But there's an easy workaround for this limitation.  If you're using Visual Studio Express, and want to have your types generated before the build process/verification of your main web project, you can create a standard dummy "Class Library".  In the pre-build event for your dummy "Class Library" you can setup Slink to execute.  Then, add the dummy "Class Library" to your main web-project.  Now, anytime you build your website, your class library will be built first (and slink will run) before the build / verification process takes place on your main web-project.

That all!  After building web project (if you're using the VS.NET Slink Plug-In) or when you execute Slink.exe, you should get a file named <WebProject>\App_Code\Slinks.cs that contains your type safe URL generated code.

If you have any questions, comments, or suggestions please feel free to contact me. I hope other developers find the Slink framework useful.  Happy coding!


Slink CodePlex Project

http://codeplex.com/slink

 

Thoughts & future improvements to Slink

  • Add support for strongly typed parameter passing/parsing for query string parameters.
  • Create a standalone Slink Plug-In that does not rely on DXCore.
  • Implement more advanced code generation caching.
  • Possibly implement /code generate a helper methods on media types such as "MyImage.GetStream()" that would automatically open and return an IO stream.

 

Licence

This library and code generator is licensed under the terms and conditions defined in the GNU Public License. You are free to use it for non-commercial purposes. If you are going to use any part of it in a commercial application, contact me and we can work something out.  You may use the code generated output of Slink in both commercial and non-commercial applications.

Special Thanks

Special thanks and acknowledgements go out to Philip Laureano for building his open source TaHoGen code template generator.  Without it, Slinks would not exist.