So I started thinking that it would be nice if we could develop a sort of plugin feature where our developers could just create a control from their application that we could just "plugin" to the parent project and it would automatically use the existing resource files and MasterPages. This would mean that the developers could just focus on the code without worrying so much about the layout or implementing security in their individual applications.
The idea I finally came up with was to create a custom route that could be used to point all requests to a single page that contained a placeholder that would load a UserControl based upon the url path. This seemed like a decent solution if I could get it to work so I went about trying to implement it in a test solution.
First, I made a web page that would load the UserControl, I just used the Default.aspx page but you could use anything:
The Default.aspx page
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:PlaceHolder runat="server" ID="UserControlPlaceholder" />
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
Default.aspx.cs
public partial class _Default : System.Web.UI.Page
{
public string Directory
{
get
{
object temp = ViewState["Directory"];
return temp == null ? string.Empty : (string)temp;
}
set { ViewState["Directory"] = value; }
}
public string UserControl
{
get
{
object temp = ViewState["UserControl"];
return temp == null ? string.Empty : (string)temp;
}
set { ViewState["UserControl"] = value; }
}
protected override void OnInit(EventArgs e)
{
// To load a UserControl the UserControl property needs to have a value
if (!string.IsNullOrWhiteSpace(UserControl))
{
// If the Directory property has a value then the path to the
// user control is "~/UserControls/Folder/UserControl
// otherwise the path is "~/UserControls/UserControl
string path = string.IsNullOrWhiteSpace(this.Directory) ?
string.Format("~/UserControls/{0}.ascx", this.UserControl) :
string.Format("~/UserControls/{0}/{1}.ascx", this.Directory, this.UserControl);
Control temp = LoadControl(path);
// We set the ID of the UserControl so that it can be maintained by ViewState
temp.ID = UserControl;
if (temp != null)
{
UserControlPlaceholder.Controls.Add(temp);
}
// Here we make the title of the page equal to the name of the UserControl
Page.Title = this.UserControl;
}
base.OnInit(e);
}
}
Next, I needed to create a custom RouteHandler that implements IRouteHandler:
public class TestRouteHandler : IRouteHandler
{
// This is the virtual path to the file containing the place holder
private readonly string virtualPath;
public TestRouteHandler(string virtualPath)
{
this.virtualPath = virtualPath;
}
public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
{
// This creates the page containing the place holder
_Default d = BuildManager.CreateInstanceFromVirtualPath(this.virtualPath, typeof(Page)) as _Default;
// This creates the virtual url being requested. It is passed into
// the UrlAuthorizationModule to check that if the user is authorized
// to view the requested page
string path = "~/Parent";
// The Directory allows us to place user controls in folders to group
// them by application
if ( requestContext.RouteData.Values.ContainsKey("directory"))
{
d.Directory = requestContext.RouteData.Values["directory"] as string;
path += string.Format("/{0}", d.Directory);
}
// This is the name of the UserControl to load
if (requestContext.RouteData.Values.ContainsKey("control"))
{
d.UserControl = requestContext.RouteData.Values["control"] as string;
path += string.Format("/{0}", d.UserControl);
}
if (!UrlAuthorizationModule.CheckUrlAccessForPrincipal(path, requestContext.HttpContext.User, requestContext.HttpContext.Request.HttpMethod))
{
requestContext.HttpContext.Response.StatusCode =
(int)HttpStatusCode.Unauthorized;
requestContext.HttpContext.Response.End();
}
return d;
}
}
Next, I needed to update the Global.asax file to register the new RouteHandler
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private static void RegisterRoutes(RouteCollection routes)
{
// This route loads just the default page without a UserControl
// when the url entered is "http://mywebsite.com/Parent"
routes.Add("Home", new Route
(
"Parent/",
new TestRouteHandler("~/Default.aspx")
));
// This route loads the default page with a UserControl
// when the url entered is "http://mywebsite.com/Parent/UserControlID"
routes.Add("Parent", new Route
(
"Parent/{control}",
new TestRouteHandler("~/Default.aspx")
));
// This route loads the default page with a UserControl from a subfolder
// when the url entered is "http://mywebsite.com/Parent/Folder/UserControlID"
routes.Add("Child", new Route(
"Parent/{directory}/{control}",
new TestRouteHandler("~/Default.aspx")
));
}
}
Now, in order to allow the WebForms application to use Routing, I needed to add a couple of lines to my Web.config file.
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule"
type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</modules>
<handlers>
<add name="UrlRoutingHandler"
preCondition="integratedMode"
verb="*" path="UrlRouting.axd"
type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</handlers>
After all of this was done, I made a second web application where I created my test UserControl. After compiling the second application I moved the UserControl.ascx file into a folder called "SiteOne" inside of the "UserControls" folder in my parent application and copied the .dll file from the bin of the second application into the bin of the parent application. I didn't need to include the .cs file for the UserControl because the code is compiled into the dll for the project.
Finally, it was time to test the routing with the new UserControl. I fired up the application and entered my custom route, http://localhost/Parent/SiteOne/Test, and sure enough there was the child application's UserControl being displayed and working without a problem.





MultiQuote


|