Embed Global.asax in assembly - c#

Is it possible to embed the Global.asax file into an assembly? Currently it is represented as a file in the web root directory. But I want to store it as a resource in an assembly.

I'm not sure. Have you tried setting Build Action to Embedded Resource? You can do that by selecting the global.asax file and then the option should appear in your property window.

Ali Reza Dehdar's answer is correct (just change Compile to Embedded Resource in file's properties) and the result can be seen using a decompiler:

Yes you can. You have three options as far as I know:
Use HttpModule but be aware that there are some tricky parts about it. For example the HttpModule Init method might be triggered multiple times (this is based on the number of application instances in the app pool)
Use OWIN
Alternate the HttpApplication type - this one works best for me but I haven't tested it in too many different situations and framework versions. The only thing you need to do in your assembly is paste the following:
.
using System.Web;
using System.Web.UI;
[assembly: PreApplicationStartMethod(typeof(MyAssembly.MyHttpApplication), nameof(MyAssembly.MyHttpApplication.Application_Register)]
namespace MyAssembly
{
public class MyHttpApplication : HttpApplication
{
public static void Application_Register()
{
PageParser.DefaultApplicationBaseType = typeof(MyHttpApplication);
}
protected void Application_Start()
{
// TODO: Your application startup magic :)
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
// TODO:
}
}
}
Trace (or something like that):
System.Web.UI.PageParser.DefaultApplicationBaseType
System.Web.Compilation.BuildManager.GetGlobalAsaxType()
System.Web.HttpApplicationFactory.CompileApplication()
Hope that helps :)

Related

How to test a single page in .aspx.net project

The project contains files of .aspx.cs , .aspx , .htm , .cs etc. As far as I understand, it is a web application project. I am working on a base page named PageBase.cs which includes features that all other pages would inherit from. I want to test how this page works and I am stuck.
There's no "Start Debug" nor "Run" options. The only one I get is "Attach to a Process". When I attached this .cs file to a process, VS shows that debug is ready but no outcomes are shown. I'm not even sure what outcomes I am expecting though so I can only stop debugging. The followings are the links I found in my research, hopefully they would be helpful in some way:
https://msdn.microsoft.com/en-us/library/3s68z0b3.aspx
https://msdn.microsoft.com/en-us/library/df5x06h3(v=vs.110).aspx
I know this question is trivial but I am totally new to .Net. Please help.
Since you've only created a class, you need to have a way to reach that code. Have one of your pages inherit from that class, and make sure that your custom class is wired into the Page Life cycle events properly (Page_Load, Init etc) depending on when you want the code to execute.
Assuming you set up the inheritance properly, and that your debugger is attached to the process, your breakpoints in the class will be hit when you access that page and hit the appropriate stages in the page lifecycle.
This is what I did for PageBase.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Test.Lib.Base
{
public class PageBase : System.Web.UI.Page
{
#region Method
protected override void OnInit(EventArgs e)
{
AutocompleteOff();
base.OnInit(e);
if (User.Identity.IsAuthenticated)
ViewStateUserKey = Session.SessionID;
}
protected override void AutocompleteOff()
{
Page.Form.Attributes.Add("autocomplete", "off");
}
#endregion
}
}
And then for other pages under test folder, (Body.aspx.cs for instance) I added PageBase as the following:
public partial class PostLogin : Lib.Base.PageBase
{
# Method
...
}

Dynamically load ASP.NET Page from DLL

I want to create a modular ASP.NET application. Something like, I have a main application that is just some kind of module loader. It only have the one "Default.aspx" page. And, based on the loaded modules, this page will create a menu and links to the pages found in the modules.
I want the modules to be ASP.NET projects packed into dll. So, I want to drop that dll into the "Modules" folder of my main application, it will identify the module, and use reflection to load the modules, inspect them to find the pages, and build a menu from that.
What I've done so far:
In my solution, I have a "DummyModule" project. This project have only 3 pages. Nothing special about it.
And I have another project called "MainApp". Here is the "big deal".
In this project I have a "ModuleLoader" class. When the "LoadModules" method is called, it search for "dll" files in the "Modules" folders of my application. And, using reflection, load these modules. Foreach of these modules, still using reflection, it searches all "Page" types, and stores the names into a list.
On the "Page_Load" method of the "Default.aspx" page, it call de "ModuleLoader" class, gets all modules names and all pages names for each module, and build a menu from that. I created a hyperlink pattern, that have all the information I need to load the right page. That is : "/ModuleName/PageName".
I'm not using the "aspx" extension. OK, so far, so good.
Here is the tricky part.
I've created a HTTPModule called "PageLoaderModule". This modules intercepts all requests, so I can read the URL to identify wich page from wich module I have to load.
And that's exactly what I cannot do and I have no idea how to solve this.
What I'm doing:
public class PageLoaderModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
//clean-up code here.
}
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
private void context_BeginRequest(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
if (Regex.IsMatch(application.Request.RawUrl, #"/.+/.+"))
{
var parts = application.Request.RawUrl.Split('/').Where(u => !string.IsNullOrWhiteSpace(u)).ToList();
IHttpHandler page = ModuleManager.GetPage(parts[0], parts[1]);
page.ProcessRequest(application.Context);
}
}
#endregion IHttpModule Members
}
The "GetPage" method, find the correct "Page" type in the specified assembly, create an instance and return the that Page instance.
But when I call the "ProcessRequest" method of the IHTTPHandler interface, it doesn't load the page.
It's possible to do that? Any thoughts?
Edit:
I've tried #Slavo suggestion.
While searching for an anwser, I've found and tried a similar solution, implementing my own VirtualPathProvider and VirtualFile.
It almost worked. The virtual path handle and load the correct page but, when the page is loaded, I got the following error in my browser:
Parser Error Message: Could not load type 'DummyModule.Pages.DummyPage3'.
Source Error:
Line 1: <% # Page Language="C#" AutoEventWireup="true" CodeBehind="DummyPage3.aspx.cs" Inherits="DummyModule.Pages.DummyPage3" %>
So, I don't know if I've done something wrong, or this isn't the solution I'm looking for. So, I tried other option.
I correctly marked the "Build Action" of the ".aspx" file as "Embedded Resource", so it can be accessible as a virtual path. But I still got the error above.
This looks like a case where you would want to write a VirtualPathProvider. This class lets you control the logic, which provides components to the compilation system.
When ASP.NET compiles a page to handle the request, by default it only uses the ASPX file and the code-behind. If you write a custom VirtualPathProvider, you will be able to tell it to do otherwise. So whenever ASP.NET needs to compile a page for a particular path to handle the request, your provider can extract it from an assembly.
Here is a helpful article: http://support.microsoft.com/kb/910441
You should handle the PostMapRequestHandler event in your module and set a custom IHttpHandler to the application.Current.Handler property. Here is an example.

Where does OnAfterInstall event go?

I've had serious problems on how to solve this: I don't know where the OnAfterInstall event goes.
Let me explain myself. I created a C# project which compiles perfectly and built in Release mode. After that, I've created a Setup Project using the wizard. I have added an extra dialog, which lets the user choose between two languages. Now, my problem is that I want to store that language into the registry (or app.config file, the easier the better), and I've read that you need to detect it within the OnAfterInstall method in an inherited class of Installer.
Now, where should I put that class? Logic tells me it goes in the C# project, but it complains that neither Context nor Installer class exist. When I add this class to the Setup Project, it doesn't complain, but it doesn't work after that. Here's the class.
using System;
using System.Configuration.Install;
public class Install : Installer
{
public Install()
{
}
protected override void OnAfterInstall(IDictionary savedState)
{
string lang = Context.Parameters["lang"];
RegistryKey key = Registry.LocalMachine;
using (key = key.CreateSubKey(#"SOFTWARE\MyCompany\MyApp"))
{
key.SetValue("lang", lang);
key.Close();
}
base.OnAfterInstall(savedState);
}
}
PS: I'm already passing lang as CustomActionData using /lang=[LANG] (where LANG is the radio value)
First, you should add the RunInstallerAttribute to you class.
[RunInstaller(true)]
public class Install : Installer
...
Next, put the installer in a separate project (class library), e.g. MyCustomInstaller.
Finally, add the primary output of this project to a custom action in the custom actions editor of the setup project.
It's up to you in which custom action you want to use.

Dependency Injection - Choose DLL and class implementation at runtime through configuration file

I've an API DLL (API.dll, for example) which, in addition to many other thinks, makes available an abstract class (AbstractClass).
Now making use of that AbstractClass I've implemented it on two different dlls:
First.API.Implementation.dll with ConcreteImplementation1
Second.API.Implementation.dll with ConcreteImplementation2
Both ConcreteImplementation1 and ConcreteImplementation2 are implementation of the same abstract class.
What I want is an application where I can choose which of those two dlls to use and, through that, choose which implementation to use without the user having to change anything within the code and, if possible, without stopping the application.
Some configuration file where I can bring the application to use whatever implementation I want. Something like:
<appconfiguration>
<implementation_to_use>
<dll>First.API.Implementation.dll</dll>
<class>ConcreteImplementation1</class>
</implementation_to_use>
</appconfiguration>
I know near to nothing about dependency injection, apart from its concept, but I guess thats the perfect fit for this task.
I've researched several DI/IoC libraries but I'm not familiar with all the concepts and names. I can use whatever library I want. For what I can say these are the most used: StructureMap, Ninject and Sprint.NET
Moreover, apart from all the dlls and implementation I need to indicate a file to be used by that application. Can I indicate its path in that same file?
I just need some tips and directions to implement such a thing. Some examples using one of those libraries, would be awesome.
Thanks.
To get you started using StructureMap, create a console application, include in it:
structuremap.config:
<?xml version="1.0" encoding="utf-8" ?>
<StructureMap MementoStyle="Attribute">
<DefaultInstance
PluginType="DemoIoC.AbstractBase,DemoIoC"
PluggedType="DemoIoC.ConcreteImplementation1,DemoIoC"
Scope="Singleton" />
</StructureMap>
The PluginType and PluggedType attributes are "FullyQualifiedClassName,AssemblyName"
By default it will look for assemblies in the executable folder, I'm not sure how you would specify another location for the assemblies
There are plenty of options for Scope, e.g. Singleton, Transient, etc
Program.cs:
namespace DemoIoC
{
using System;
using StructureMap;
public static class Program
{
public static void Main(string[] args)
{
// here you initialize structuremap from the config file.
// You could probably use a FileSystemWatcher to reinitialize
// whenever the structuremap.config file changes
ObjectFactory.Initialize(x =>
{
x.UseDefaultStructureMapConfigFile = true;
});
var concrete = ObjectFactory.GetInstance<AbstractBase>();
concrete.Method1();
Console.ReadKey(true);
}
}
}
AbstractBase.cs:
namespace DemoIoC
{
public abstract class AbstractBase
{
public abstract void Method1();
}
}
ConcreteImplementation1.cs:
namespace DemoIoC
{
using System;
public class ConcreteImplementation1 : AbstractBase
{
public override void Method1()
{
Console.WriteLine("Called ConcreteImplementation1");
}
}
}

Extension methods in a class library project

I've implemented some extension methods and put those in separate Class Library project.
Imagine I have a simple extension method like this in class library called MD.Utility:
namespace MD.Utility
{
public static class ExtenMethods
{
public static bool IsValidEmailAddress(this string s)
{
Regex regex = new Regex(#"^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$");
return regex.IsMatch(s);
}
}
}
But nowhere in the web app like the App_code folder or the WebFroms code-behind page can I use this extension method. If I do something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using MD.Utility;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string email = "Someone#Somewhere.com";
if (email.IsValidEmailAddress())
{
//To do
}
}
}
The compiler doesn't recognize IsValidEmailAddress() and there's even no IntelliSense support.
While if I put my extension method in the App_Code folder, it's usable in another .cs files in the App_code folder or the WebForms code-behind pages.
Did you remember to add a reference to your class library in the web project ?
You will need that. Other than that, your code looks fine, and should work.
If changes are not getting recompiled when you do a solution rebuild, then it could be the type of reference you are using. If the MD.Utility project is in your web project solution, you should make the reference a "Project Reference." That will cause the build to consider that code as a dependency and therefore rebuild it when you change something. If you just include it as a DLL, then the DLL is considered external and the build will not consider it, even if it is in the same solution.
I was able to resolve it by making the extension module public.
This post may be helpful:
Extension methods in referenced assemblies?
In addition to adding the assembly to the references, what fixed it for me was to explicitly adding it to the file "using MD.Utility".
I've found that this can occur if the Assembly Name and Namespace of the consuming project are the same and the Common library has the same Namespace.
Seems that the compiler gets confused. Try changing them.
As noted elsewhere, you need to add the Common library to each consuming project. And the Module containing the Extension(s) in the Common library must be marked Public. Unlike Classes, Public isn't the default scope for Modules. No idea why.

Categories

Resources