Friday, September 09, 2005

Embedding static files inside a .NET assembly

Any web application contains static data like images, scripts, text etc.These can be embedded in the assembly itself instead of distributing them as separate files.Advantages are obvious.
1. You do not need to worry about their exact location.
2. You only have one .dll file to be shipped (so you can use XCOPY deployment)

I was creating a Custom server control that uses images and script files.Instead of shipping them separately with the control assembly, I was looking for ways to embed it into the assembly itself. I found many ways of doing it. I'm going to discuss two of the ways (to store script files) in this post.

One way:

Step 1. Embedding:

1. Add a .resx file to the projectA .resx file stores information in the XML format.Specifically, the section stores the key-value pairs.[Note: You could also create a .txt file to store your static data. But it can only hold text data. Inorder to store images or objects, you have to use .resx files]

MyProject

------ MyStaticFiles.resx

------ MyCode.cs

2. Open the .resx file in the Visual Studio editor.Give some name, say, "ClientScript", to your script that you can use in your code to access it.In the value field, copy all the client script (static data) you want to be rendered.

3. Set the build type of the .resx file to be Embedded Resource, and not Content.This informs the compiler that the file's contents should be embedded in the assembly.[In visual studio you can change the Build Type when you right click on the file and go to Properties.]

4. Build the project as you normally would.Once you build the project, the file structure is as follows...

MyProject

------ MyStaticFiles.resx

------ MyCode.cs

------ bin

------------ Debug

------------------ MyProject.dll

------ obj

------------ Debug

------------------ MyProject.MyStaticFiles.resources

5. Now a .resources file is automatically created for you that has the same name as the .resx file. The name of the output resources file will then be MyStaticFiles.resources.
The physical location of this file is \obj\Debug

[Note: You can also manually create a .resources file from a .resx file using the following commandresgen MyStaticFiles.resx MyStaticFiles.resourcesresgen can only convert .txt or .resx files in to .resources files and vice versaIt can also convert .txt and .resx in to each other.]
This .resources file has been embedded in the resulting project's assembly.You can confirm this fact in one of the 2 ways.

1. By looking at the assembly manifest using Ildasm.exe, shipped with .NET SDK.
[Ildasm.exe is a takes a portable executable (PE) file that contains Microsoft intermediate language (MSIL) code and creates a text file and can be found on your machine somewhere at \Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin]

The assembly manifest should contain an entry as follows...
.mresource public namespaceName.MyStaticFiles.resources
{
}

where namespaceName is your project's namespace.

2. Programmatically
The following statement can be used to get an array of all resource names, embedded in the current assembly.

string[] mRNames = this.GetType().Assembly.GetManifestResourceNames();

In our case, it should just be one and that is, namespaceName.MyStaticFiles.resources.


Step 2: Shipping

All you have to ship is the assembly, ie., MyProject.dll. It has the executable code as well as the static data (client script)


Step 3: Accessing

Now that you have data embedded in the assembly, how do you go about retrieving it?

Create a ResourceManager object for this assembly, get the resource set and access the required object using the Key.

ResourceManager manager = new ResourceManager( this.GetType() );
string script = manager.GetResourceSet(System.Globalization.CultureInfo.CurrentCulture, true, true).GetString("ClientScript");

If you have stored an object in the .resx file, you would use GetObject() method of the ResourceSet class, instead of the GetString() method. And then you have to cast it back to the appropriate type.


Another way:

Step 1. Embedding:

1. Add your static data file to the project (you can create a folder to store all your static data files)

MyProject

------ MyStaticFiles

------------ MyClientScript.js

------ MyCode.cs

2. Set the build type of all of the static files to be Embedded Resource, and not Content.This informs the compiler that the file's contents should be embedded in the assembly.[In visual studio you can change the Build Type when you right click on the file and go to Properties.]


3. Build the project as you normally would.
Once you build the project, the file structure is as follows

MyProject

------ MyStaticFiles

------------ MyClientScript.js

------ MyCode.cs

------ bin

------------ Debug

------------------ MyProject.dll

4. Now the static file MyClientScript.js has been embedded in the resulting project's assembly.
You can confirm this fact in 2 ways.

1. By looking at the assembly manifest using Ildasm.exe.
The assembly manifest should contain an entry as follows...

.mresource public namespaceName.MyStaticFiles.MyClientScript.js
{
}
where namespaceName is your project's namespace.

2. Programmatically
The following statement can be used to get an array of all resource names, embedded in the current assembly.

string[] mRNames = this.GetType().Assembly.GetManifestResourceNames();

In our case, it should just be one and that is, namespaceName.MyStaticFiles.MyClientScript.js


Step 2: Shipping

All you have to ship is the assembly, ie., MyProject.dll. It has the executable code as well as the static data (client script)

Step 3: Accessing

Now that you have data embedded in the assembly, how do you go about retrieving it?
Load the specified Manifest resource from this assembly and convert the resulting stream into a string.

System.IO.Stream scriptStream = this.GetType().Assembly.GetManifestResourceStream(".MyStaticFiles.MyClientScript.js");
byte[] buf = new byte[scriptStream.Length];

scriptStream.Read(buf,0,Convert.ToInt32(scriptStream.Length));

The following line converts the byte array to a string.
string script = System.Text.Encoding.Default.GetString(buf));

2 Comments:

At 1:04 PM, Blogger Jessica Klarkson said...

This is a excellent blog. Keep it going. Here's the resolve a lot of people are searching for; how to buy & sell everything, like classic video game on interest free credit; pay whenever you want.

 
At 1:09 PM, Blogger Jon said...

I don't bother reading many blogs but I really like your's. Well done on adding something good to the rubbish that usually fills blogs.

My site is on permanent cure for acne related goodies. It pretty much covers most permanent cure for acne subjects.

If you get time, pop in and have a look

Thanks

 

Post a Comment

<< Home