Providing images from. NET Assemblies (ii)

Source: Internet
Author: User
Tags config contains decrypt hash http request httpcontext sort urlencode
Program Directory:
Enhanced Code
Finishing
Security
Summary
About the author

Enhanced Code

The first thing to handle in your code is the case. HTTP considers all of the following URLs to be the same, because the URLs are case-insensitive.







Our code currently has a problem, because it does not preserve the original HTTP request case-insensitive features, so you must add some code to the Loadandreturnimage function.

Case insensitive

What we're going to do is load the image from the assembly regardless of the case, but because the assembly.getmanifestresourcestream is case-sensitive, we have to find another way. The Assembly.getmanifestresourcenames () function returns a list of all the resources in a given assembly, so all we have to do is call this list, do a case-insensitive comparison with these resource names, and then use the names that are found:

Assembly Resourceassem = Assembly.Load (Assembly);

Find the name of the cache
string[] names = HttpContext.Current.Application [assembly] as string[];

if (null = = names)
{
Gets the names of all resources in the Assembly
names = Resourceassem.getmanifestresourcenames ();
Array.Sort (names, caseinsensitivecomparer.default);
HttpContext.Current.Application [assembly] = names;
}

If there are some resources in this Assembly,
Check the required resources
if (names. Length > 0)
{
Find an image in an array of names
int pos = Array.BinarySearch (names, image,
Caseinsensitivecomparer.default);

if (pos >-1)
Writeimage (Resourceassem, Names[pos], true);
}



Here I loaded the assembly that contains the resource, and then look for the application cache to see if the list of resources in that assembly has been loaded and cached. If not, I read the list of resources by calling Assembly.getmanifestresourcenames (), and then sort the list and store it in the application state.

Then, I can use the Array.BinarySearch () method to perform a binary search on the list of names. This is much faster than sequentially searching the list of strings, and the system overhead required to store the resource list in application state is also small.

This solves the case-sensitivity problem, but what about performance? At present, every time an image request arrives, we call all the code-except for the smallest Web site, all the other requests can cause serious performance problems. We will deal with this issue in the next section.

Cache

As with normal images and some ASPX pages, caching images returned from an assembly is useful-because these images reside in an assembly and generally do not change frequently.

If we are writing a simple ASPX page, you can add OutputCache directives to cache the page. But in our scenario, we need a way to programmatically add a cache control header to the response stream. Luckily, it's easy to do in asp.net. In a function that writes an image to the output stream, simply add the following lines:

Response. Cache.setexpires (DateTime.Now.AddMinutes (60));
Response. Cache.setcacheability (Httpcacheability.public);
Response. cache.varybyparams["Assem"] = true;
Response. cache.varybyparams["image" = true;
Write image to Response stream ...



This setting causes the image to expire after an hour (which obviously can be extended to reduce the server load) and defines that the image can be cached anywhere (client, proxy, server, etc.). It also defines the parameters for changing the caching behavior. Now, the code is almost complete, but we need to decide how to handle the exception.

Programming on exceptions

A lot of exceptions can be thrown in our code. The user's browser may now be disconnected and may even still encounter the ASP.net error page. We can speculate on a number of possible scenarios. As shown below:

• The assembly may not exist.
• The assembly exists but does not contain any images.
• The assembly may not contain the requested image.

The code may also cause other errors. When the image is not found, the default response of the browser is to return an image with the Red Cross to indicate a broken link.

You certainly want to replace this image with your own default image. I have included a default broken link image in the Imageserver assembly, and when an exception occurs, the image is returned to the browser. This behavior can be implemented by adding a setting to the AppConfig section of the Web.config file.

When an error occurs, if you want to overwrite the default behavior (the exception on the return chain), add the following to the web.config.

<appSettings>
<add key= "Mfrshowbrokenlink" value= "true"/>
</appSettings>



Now, when an exception occurs in your code, a disconnected image is returned to the browser and a warning is written to the trace log.




Figure 4: The image returned when the link is disconnected


If you view the trace log, you see an entry that does not exist for the image, which is similar to the following.




Figure 5: Sample trace log output for invalid image requests


All the code discussed in this article is available through the MFRImages.exe download link at the top of this page. This download includes all the enhancements that are done in this section. Also includes test pages that allow you to view the results of rendering images using handlers and ASPX methods.

Finishing

Add a method to return the correct URL of an image that resides in the assembly, and then the custom control writer (or you) can call this method to return the image.

If you have selected a handler method to provide an image, the function you need is as follows.

public static string Constructimageurl (Assembly Assembly, string image)
{
return string. Concat (". mfr?assem=",
Httputility.urlencode (assembly. Fullname.tostring ()),
"&image=",
Httputility.urlencode (image));
}



For this piece of code, I'm using string. Concat (), because it is more than string. The Format () is approximately 4 times times faster. Every little trick will help! You can then use it to set the ImageURL property of all the images that you create in your custom control.

Security

For the discussion so far, we have been providing images based on the assembly name and resource name. That's OK, but it means anyone can get the assembly name on the disk and try to attack by passing the other assembly names to the handler.

To avoid this potential problem, it is a good idea to encrypt the returned value in some way. We can provide some hash code generated from the assembly name and image name, or use the assembly name and image name encryption format, and then decrypt the request after receiving it.

The previous method (using the hash code) requires a lookup table in the server, and the table fills in the content for each provided image. This poses a potential problem for the WEB domain. In the Web realm, it is possible for a server to provide an initial image request (and cache the hash code) while another server actually responds to the image.

Therefore, I chose the second method, which contains the encrypted assembly name and image name in the URL that is returned to the user. This will not be a problem in the Web domain, but it means that you need to send some more data from the browser to the server because the image URL is longer.

The sample code contains a class that encrypts and decrypts strings using the Triple-des (Data Encryption Standard) algorithm. Typically, the assembly name and image name are encrypted before being passed to the client. When the image is requested, the values are decrypted and the same code is invoked.

I've added these content to the solution in a configurable way. There is only one flag in Web.config, and if set to true, it is encrypted when the resource name is supplied to the client:

<appSettings>
<add key= "Mfrsecure" value= "true"/>
</appSettings>



In the ProcessRequest method of the handler, I check this tag:

BOOL secure = false;
String shouldsecure = configurationsettings.appsettings["Mfrsecure"];

if (null!= shouldsecure)
Secure = Convert.toboolean (shouldsecure);

String assembly = Context. request.querystring["Assem"];
String image = Context. request.querystring["image"];

if (secure)
{
Assembly = crypto.decrypt (assembly);
Image = Crypto.decrypt (image);
}

Manifestimageloader.renderimage (assembly, image);



Similarly, in the Constructimageurl method described earlier, I encrypted the assembly name and image name before being passed to the client. Many parts of the code can be extended or improved. Here are a few of my suggestions.

• When a resource cannot be found, the configuration item does not hard-code the image being used, but instead specifies the URL of the image. This way, when an exception occurs, you can load a specific image from a disk (or from another assembly) and return it to the browser. • The cache timeout for an image can also be defined as a configuration item.
• You can extend the code to allow any type of image to be supplied from the assembly-currently, the MIME type is hard-coded to Image/gif.
• There is no reason why the code in this example cannot provide other resources in the assembly-you can provide TXT files, WAV files, and so on.

Summary

This article describes two methods for retrieving images from an assembly that fit within a Web site. The first approach is to provide an image from an ASPX page, which is simple and does not require a WEB server configuration to be modified, but the path to the ASPX page that provides the image must be correct so that the image is displayed correctly.

Another approach is to provide an image from a custom handler. This approach overcomes the path-based constraints, but requires changes to the IIS metabase to allow the Aspnet_isapi.dll Extender to provide a. mfr extension. You also modify the web.config for a given application. I personally recommend using a handler method rather than an ASPX method, because it is easier to use (and not require a path) when the handler method is configured on the WEB server.

About the author

Morgan is a Microsoft application development advisor working in the UK specializing in Visual C #, controls, WinForms, and asp.net. Since the PDC was released in 2000, he has worked on. NET and has been very fond of. NET, so he joined the company. His homepage is http://www.morganskinner.com/, where you can find links to other articles he writes. In his limited leisure time, he likes weeding in his own garden or enjoying a few unique dishes of meat-baked bread.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.