Reputation: 47
Is there a way to add <%%> blocks to a page or control at run time or execute a block of code and insert the results in the control/page?
This is specifically for an C# ASP.net compiled web application Framework 4.5 If not, is there another way of doing this which would result in the same? I want users to be able to add simple things without editing the ascx or aspx pages.
e.g.
Upvotes: 1
Views: 2014
Reputation: 47
Not sure how efficient the below is, but it seems to work without having to write the ascx to the hard disk.
You add the code to the VirtualCompiler with a unique name and the code as parameters.
VirtualCompiler.Add("MyName", @"<%@ Control Language=\"C#\" AutoEventWireup=\"false\" CodeBehind=\"...\" Inherits=\"...\" %>\r\n<% Response.Write(DateTime.Now);\r\n%>");
Then to load the control:
Page.Controls.Add(Page.LoadControl("~/DynamicCode/MyName.ascx"));
Classes below
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
namespace Admin.UI.Utility
{
public class VirtualCompiler
{
protected static Dictionary<String, String> _code = new Dictionary<String, String>();
public static void Add(String Name, String Code)
{
Name = Name.ToUpper();
if (_code.ContainsKey(Name))
_code.Remove(Name);
_code.Add(Name, Code);
}
public static String Get(String Name)
{
Name = Name.ToUpper();
if (_code.ContainsKey(Name))
return _code[Name];
return String.Empty;
}
public static Boolean Exists(String Name)
{
Name = Name.ToUpper();
return _code.ContainsKey(Name);
}
}
public class VirtualControl : VirtualFile
{
public String WebControlContent = String.Empty;
public VirtualControl(String VirtualPath)
: base(VirtualPath)
{
int ndx = VirtualPath.LastIndexOf("/");
String filename = ndx >= 0 ? VirtualPath.Substring(ndx + 1) : VirtualPath;
WebControlContent = VirtualCompiler.Get(filename);
}
public override System.IO.Stream Open()
{
MemoryStream ms = new MemoryStream();
if (!String.IsNullOrWhiteSpace(WebControlContent))
{
byte[] data = System.Text.ASCIIEncoding.ASCII.
GetBytes(WebControlContent);
ms.Write(data, 0, data.Length);
}
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
}
public class VirtualControlProvider : VirtualPathProvider
{
public static void AppInitialize()
{
VirtualControlProvider db = new VirtualControlProvider();
System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(db);
}
public override CacheDependency GetCacheDependency(string VirtualPath, IEnumerable VirtualPathDependencies, DateTime UTCStart)
{
return IsPathVirtual(VirtualPath) ? null : base.GetCacheDependency(VirtualPath, VirtualPathDependencies, UTCStart);
}
private bool IsPathVirtual(string VirtualPath)
{
String checkPath = VirtualPathUtility.ToAppRelative(VirtualPath);
return checkPath.StartsWith("~/DynamicCode/".ToLower().ToString(), StringComparison.InvariantCultureIgnoreCase);
}
public override bool FileExists(String VirtualPath)
{
if (IsPathVirtual(VirtualPath))
{
VirtualControl file = (VirtualControl)GetFile(VirtualPath);
// Determine whether the file exists on the virtual file
// system.
if (file != null && !String.IsNullOrWhiteSpace(file.WebControlContent))
return true;
else
return Previous.FileExists(VirtualPath);
}
else
return Previous.FileExists(VirtualPath);
}
public override VirtualFile GetFile(String VirtualPath)
{
if (IsPathVirtual(VirtualPath))
{
return new VirtualControl(VirtualPath);
}
else
return Previous.GetFile(VirtualPath);
}
}
}
Upvotes: 0
Reputation: 171236
Maybe the simplest way to do this is to create .ascx
files at runtime in some temporary directory. Then, you can reference these files using (Html.RenderPartial
or any other similar way). This will trigger a compilation at runtime and pretty much all the work should be done for you.
Also, it is important to realize that this ability gives users the power to run arbitrary code on your server including database access.
Upvotes: 1