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 19.30