Tyrone
Tyrone

Reputation: 47

C# Dynamically add <% Code %> to an aspx page or ascx control

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

Answers (2)

Tyrone
Tyrone

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

usr
usr

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

Related Questions