[ENG] Assign a Strong Name to an aspx page

Marco Barzahi [MVP Visual Developer - ASP/ASP.NET]
Italian Version

Have you ever tried to assign a  Strong Name to an aspx page? In this article we will try to find a solution that could not follow the standard guidelines. In this article I use also terms "mark" or "sign" an aspx page. We start defining a page  SignedPage.aspx like this:

<%@ Page language= "c#"%>
<%=GetType().AssemblyQualifiedName%>

The page does not use  codebehind and it will be compiled in c# - but the choice of language/compiler is indifferent - and,  when the page works, it will emit its AssemblyQualifiedName .  This property will help us to know the name of the linked page class, its namespace, its assembly name with version, culture and PublicKeyToken.

The PublicKeyToken  is the indicator; when the value is null it means the page is not signed. 

If you want do a first test I recommend to use a new virtual directory or however without any other ASP.NET project present in it. More ahead we will speak about some problems we could have. If we call the page just created we will see of course a PublicKeyToken= null and a remarkable assembly name. The goal of this article is not to understand the reason of assembly name but it is a good thing to know the ASP.NET pipeline, I recommend to read the article "Code Declaration Block vs Code Render Block" (ITA) or the article "The ASP.NET HTTP Runtime" on MSDN. 

To sign our page I will try - with most classic of the solutions - to apply AssemblyKeyFileAttribute ,  as  MSDN shows; so I create snk file and a new project in which to insert SignedPage.aspx, then I assign the strong key name (.snk) adding the attribute AssemblyKeyFileAttribute into source file AssemblyInfo.cs (or .vb if you are using VB.NET).

I compile and recall again the page. The PublicKeyToken is null yet and the page is not signed. 

ASP.SignedPage_aspx, fsw44org, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

Actually it is not enough add the standard attributes into AssemblyInfo -  like it would happen in library and executable program project - because these help to define the codebehind decoration. Usually the aspx pages will be compiled on demand at runtime and it is generated a new further assembly for each one. If you analyze the "bin" folder of your testing web application you can verify that the codebehind assembly is signed. Unfortunately the page is not marked because it belongs to another assembly.

The strategy I will show is an alternative solution with which you can mark single page or all pages of the application, but we must have absolute references to file system.

The absolute references to the file system have had exclusively to poor documentations and/or however difficult management of the folder used for the compilation of the aspx page. In this article our reference folder will be  "C:\".

In a aspx page is not possible add attributes to decorate assembly and so we should try to  inject  code during its compilation. To do this we must add an extra module (source file) in which we define required attributes. Looking into documentation we can find the compilerOptions option that we can use on @page , affecting a single page, or in web.config, affecting all pages of the application. This attribute is a string containing compiler options used to compile the page and therefore we can add extra source file path. Now, I explain my idea.

In the reference folder I create the file  AssemblyKeyFileAttribute.cs (o .vb) where I define the declaration of  AssemblyKeyFileAttribute. The attribute will have an absolute reference to snk file. 

//AssemblyKeyFileAttribute.cs
[assembly: System.Reflection.AssemblyKeyFileAttribute(@"c:\MarcoBarzaghi.snk")]

Then I add the compilerOptions option into the page or into web.config, like showing by the samples. This is the point where I am really obliged to use absolute references to the file system.

<%@ Page language= "c#" compilerOptions="c:\AssemblyKeyFileAttribute.cs"%>
<%=GetType().AssemblyQualifiedName%>

<compilation defaultLanguage="c#">
  <compilers>
    <compiler language="c#"
     type="Microsoft.CSharp.CSharpCodeProvider,system, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
     compilerOptions="c:\AssemblyKeyFileAttribute.cs" />
  </compilers>
</compilation>

If we try to use the page SignedPage.aspx after to have applied one of two solutions (or both) we will see with pleasure that PublicKeyToken  is not null, howevere the page is now signed.

ASP.SignedPage_aspx, ykwa1jiy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=7c50623de4536c36

Of course an alternative attribute for AssemblyKeyFileAttribute is the attribute AssemblyKeyName, however it could avoid only the absolute reference to snk file, but not to the injecting source file.

It doesn't work!

CS1577: Assembly generation failed -- Referenced assembly '<assembly name>' does not have a strong name

If you have this error, it means that your page has references to not signed assembly, in fact a signed assembly can have only reference to other signed assemblies. Therefore it possible that you are in these situations:

  • the page have references to external not signed library.
  • the page have references to not signed codebehind class; be careful if you use codebehind classes we must sign also them.
  • the page is located in a virtual directory in which it is already present a web application with Global.asax.

The last annotation is certainly one of most interesting . I cut two code snippets to understand what it happens. The first shows the emitted code if a web application have not  Global.asax, instead the second shows the contrary situation. As easily we can see the code emitted by the page has reference to the class generated from the Global.asax, and then - if not signed - raises an error.    

protected System.Web.HttpApplication ApplicationInstance
{
 get {
  return ((System.Web.HttpApplication)(this.Context.ApplicationInstance));
 }
}

protected ASP.Global_asax ApplicationInstance
{
 get {
  return ((ASP.Global_asax )(this.Context.ApplicationInstance));
 }
}

A workaround is to add the compilation option to the  web.config or to add option only to  Global.asax , defined with  @ Application instead of @ Page, with the same option. This is not possible with Visual Studio and so we must open file with notepad.

Conclusion

"Raffaele, what do you think about this solution?"
"Good work, Markino! Your test is impeccable!"
"Thank you...  but now that we have assigned a Strong Name to a page?"

At first the question was a personal curiosity, but if we want to give a practical usage for the solution I could tell you that sometimes providers do not allow to have  full trust  with ASP.NET. If you were a provider in fact you should avoid that your users could deploy dangerous code. However the  Strong Name as evidence for the CAS is a possible usage. The folder of a web application is dynamic and so you cannot use other evidences. Actually the strong name is not easy to assign to a web application and so an alternative way should be set security level into web.config using <trust> section. In online discussions some people remind me some other scenario related with requirement  to have signed pages , for example when you must call component with StrongName LinkDemand (all running under partial trust).

The conclusion is that this article is not perhaps of daily application but sure it is an interesting exploration of the internals of ASP.NET. In version 2,0 it will be possible to mark our pages choosing precompilation; in this case a practical dialog window will be very helpful.

posted @ sabato 20 agosto 2005 22:30

Print

Comments on this entry:

# re: [ENG] Assign a Strong Name to an aspx page

Left by amol kagde at 10/09/2008 16:46
Gravatar
thank u

this article reaky help me!

# re: [ENG] Assign a Strong Name to an aspx page

Left by markino at 23/08/2010 12:10
Gravatar
** comments on this article are closed due excessive spam **
Comments have been closed on this topic.
«novembre»
domlunmarmergiovensab
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567