Mange WebPart Resources (Linked vs Embedded)

on Friday, March 12, 2010

One of the most common questions I get in class and see in the forums is how best to deal with Web Part resources. By resources, I mean those necessary files that your Web Part depends on. These include JavaScript files, images, CSS, Flash, or even Silverlight apps. With the packaging and deployment model of SharePoint, it may be challenging to figure out where to store and how to reference these files. This article will overview your deployment options and give you enough information to make the best choice for your resource needs.

Linked or Embedded

With resource files, you have two basic options: linked or embedded. Linked means your Web Part will point to the file that lives somewhere in the file system. This is the most common approach. Embedded means you store the actual resource file inside your Web Part assembly. While less common, this can be very useful in many cases. We’ll look at each of these in more detail.

Linked Resources

Linked resources work best if you’ll need to modify the resource file separately from the Web Part. For example, say your Web Part references a JavaScript file and you continually need to tweak it and don’t want to recompile and redeploy the Web Part. If you link to it, it’s easy to change, and no changes to your Web Part are necessary. When working with linked resources, SharePoint provides you two primary options.

  1. Store the resource in a virtual directory such as _wpresources (this points to C:\Program Files\Common Files\microsoft shared\Web Server Extensions\wpresources)
  2. Store the resource with the Web Application inside the inetpub\wwwroot\wss\VirtualDirectories\<80>\wpresources

For option 1, you should make sure your Web Part assembly is deployed into the GAC. This is necessary since the _wpresoures virtual directory is used across each SharePoint Web Application. We call this Farm-level scope.

For option 2, you should make sure your Web Web Part assembly is deployed in to the bin folder for the Web Application. We call this Web-Application scope.

That said, you choose which wpresources folder based on the scope of your Web Part. For both options, you’ll be placing your files inside a sub folder to keep them separate from other files in other Web Parts. The sub folder name needs to be the namespace of your project. For example, with Web-Application scope, it might go here: inetpub\wwwroot\wss\VirtualDirectories\80\wpresources\namespace.

Ok, so you’ve chosen the appropriate folder based on the scope. How would you then reference this file within your Web Part code? It’s actually pretty easy and would look like this for a JavaScript file. (Note: this code can be placed in the CreateChildControls method for the Web Part.)

//Path to resource.  This is used for a web part deployed into the GAC (Option 1)
string scriptUrl = "~/_wpresources/namespace/file.js";

//Path to resource.  This is used for a web part deployed into the bin folder (Option 2)

string scriptUrl = "~/wpresources/namespace/file.js";

//Reference Script for web page
Page.ClientScript.RegisterClientScriptInclude ("file.js", scriptUrl);
Be careful, as these are very similar. You’ll notice for the first one, that you specify _wpresources (with an underscore). Also, make sure you replace namespace with the actual namespace for your Web Part project. For an image, it would work like this:
Image myImage = new Image();
myImage.ImageUrl = "~/wpresources/namespace/image.jpg";

this.Controls.Add(myImage);


The last important detail when using linked resources is how should you deploy these files? First off, you should be using SharePoint Solutions to deploy your code. You are doing this, right? Inside the Solution manifest.xml file, there are specific tags to deploy these kinds of resources. The schema looks like this:

<Assembly Location="Namespace.dll" DeploymentTarget="WebApplication">   
   ...
   <ClassResources>

      <ClassResource Location="file.js"/>
      <ClassResource Location="image.jpg"/>
   </ClassResources>

</Assembly>
Here is where you can see that the DeploymentTarget attribute matches the scoping option. In this sample above, it is WebApplication scoped (option 2). To deploy into the GAC, replace this with GlobalAssemblyCache. To learn more about the schema inside this file, see this link.

Now that you have a good grasp on linked resources, let’s take a closer look at those that are embedded.

Embedded Resources

Embedded resources are physically stored within the Web Part .DLL file. In one way, this is nice as you can always be assured that the resources and the Web Part stay together. The drawback is that if you need to change a resource, you must recompile and deploy an updated version of your Web Part. When the client needs the resource, it is dynamically extracted from the .DLL and provided. You’ll see how.

To use an embedded resource, there are three things you need to do. The first is that you need to add the resource file to the project and mark is as an Embedded Resource. This is done via the Build Action setting inside Visual Studio as shown here.

image

The second thing you need to do is declare this resource inside the AssemblyInfo.cs file for your Web Part project. This is an easy one-liner as shown:

[assembly: System.Web.UI.WebResource("namespace.file.js", "text/javascript")]

The parameter string that is used consists of the Web Part namespace followed by the filename of the resource. The next parameter is just the MIME type. If this were an image, it could be image/jpg.

The third thing step is make sure you extract the Url to the resource. This is also one line of code as shown:

string scriptUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "namespace.file.js");

As with linked resources, you’ll then deliver this script to the page with a call to RegisterClientScriptInclude within CreateChildControls. As you would probably guess, the string here must match the name in the AssemblyInfo.cs file. As written here, the resource files need to exist in the root folder of the Web Part project. (Note: technically you don’t need to precede the file with the namespace as long as the string is unique within the project. The common convention, however, is with the namespace).

You might be curious how this actually works from the browser’s perspective. Well, what gets delivered to the browser is a link to a special, in-memory page called WebResource.axd along with a querystring to uniquely identify this specific resource. In HTML, it looks something like this:

<script src="/WebResource.axd?d=ZPJuqJGGI6qgSKsEa2PfIw2&amp;t=633527425956801634" 
        type="text/javascript">
</script>

This is how it dynamically finds the resource file, extracts it from the Web Part DLL, sets the content type, and then delivers it to the browser. Pretty cool.

Conclusion

In this post, you have seen how to both link to and embed Web Part resources. Each has its own advantages and disadvantages, mostly boiling down to whether you need to maintain the resource separately from the Web Part. In both cases, the resource file can be cached, so there is little performance difference from each option. Feel free to use one of these two approaches for your next web part.

0 comments: