pavanarya – Pavan Kumar Aryasomayajulu

Contact Email : pavan.aryasomayajulu@gmail.com

Archive for the ‘Reflection’ Category

Adding ServerSide Code(Using CODEDOM) from HTML TextBox and Making Use Of It

with 2 comments

Hi,

Requirement
I want to inject some server side code from a textbox. For example i will type a c# program in a textbox and that should be executed at server side.

Few words on how i am trying to implementation
I want to write a small web application which has a textarea and a button. We can enter some c# code inside the textbox and when we click on the button this particular code from the textbox is sent as a string and executed in the button click event dynamically and also we are creating a dll at a particular location and making use of that dll using reflection(My all time favorite topic). In order to do this we have some libraries in the .Net framework called as CODEDOM.

Actual Implementation

Microsoft.Csharp.dll contains beautiful classes. Among those beautiful classes i am trying to make use of a class called CSharpCodeProvider. This class contains methods that were used to compile and generate c# code.

One of the main method of CSharpCodeProvider that we are making use is CompileAssemblyFromSource()

 
             string sourceCode = txtBox.Value;//Contains code entered in textbox

            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters compilerParam=new CompilerParameters();

            compilerParam.GenerateExecutable=false;
            compilerParam.OutputAssembly = @"F:\My Code\ConsoleApplication1\DynamicCode.dll";
            compilerParam.GenerateInMemory = false;
          CompilerResults results= provider.CompileAssemblyFromSource(compilerParam, sourceCode);

1.So in the above code piece initially we are trying to create an object of CSharpCodeProvider.
2.CSharpCodeProvider class contains many method out of which we are trying to make use of CompileAssemblyFromSource. This method accepts 2 parameters
i.object of CompilerParameters
ii.String that contains source code.
3.CompilerParameters class is used to specify different options for the compiler. There are number of properties and methods provided by this class and we are trying to make use of few.
i.GenerateExecutable –this should be set to false we are trying to create a library. If we want to create an exe(ConsoleApplication), this should be set to true.

ii.OutputAssembly –For specifying the name of the dll or exe

4. Once we set all the information to our CompilerParameters class , we can call our method CompileAssemblyFromSource().The return type of this method is an object of CompilerResult class.

CompilerResult class contains all the information about error(if any),warnings

CompilerErrorCollection errorCollection = results.Errors;
          lbl.InnerText = "";
          foreach (CompilerError ce in results.Errors)
          {

              lbl.InnerText = lbl.InnerText + "\n" + ce.ToString() + "IsError:" + !ce.IsWarning;
              return;
          }

Now we are done with the creation of the dll successfully in the path specified by the OutputAssembly property.

Calling Dll Using Reflection

Assembly assm= Assembly.LoadFile(path);
         Type typ = assm.GetTypes()[0];
        object d= Activator.CreateInstance(typ);
           // object obj=assm.CreateInstance(typ.Name);

            object returnValue=typ.InvokeMember("kain", BindingFlags.InvokeMethod | BindingFlags.Static |BindingFlags.NonPublic, null, d, null);

1. Load the assembly. There are different methods fr doing this. If the dll is present in the root folder or in Gac then we can use Assembly.Load(AssemblyQualifiedName). If we are not sure then we can use Assembly.LoadFromFile().

2.Get the type from the Assembly. We can use assembly.GetType() and if the dll is a com component registered in the registry then we can make use of Assembly.GetTypeFromProgId().

3. Once we have type then we can use the dll like any thing. I am using InvokeMember for calling the kain method. InvokeMember accepts few parameters.

i.Method name
ii.BindingFlags is an enum and we should specify what type of method we are calling. For example our Kain method is Non public,static
iii.Binder is used for type conversion and in our case we can send it as null
iV. Object we are trying to invoke
V.parameters that we are supposed to send.

    object[] args = new object[] { "param1", "param2" };//Parameters can be sent like this
     

Complete Code

WebForm.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="CodeFromTextBox.WebForm1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script language="javascript" type="text/javascript">
// <![CDATA[

       
// ]]>
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <h1>Please enter your server side code</h1>
    
    <textarea runat=server ID=txtBox Rows="10" Columns="1000"></textarea>
    
    <asp:Button runat="server" id="genCode" OnClick="btnClick" />

    <label id="lbl" runat=server></label>
    </div>
    </form>
</body>
</html>

WebForm1.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Collections.Specialized;
using System.Reflection;

namespace CodeFromTextBox
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void btnClick(object sender, EventArgs e)
        {

            //using System;public class DynamicCodeAddingSample {    static string kain()    {        return "Testing dynamic code sample";    }}
            string sourceCode = txtBox.Value;

            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters compilerParam=new CompilerParameters();

            compilerParam.GenerateExecutable=false;
            compilerParam.OutputAssembly = @"F:\My Code\ConsoleApplication1\DynamicCode.dll";
            compilerParam.GenerateInMemory = false;
            
           StringCollection col= compilerParam.ReferencedAssemblies;

          CompilerResults results= provider.CompileAssemblyFromSource(compilerParam, sourceCode);
            
          CompilerErrorCollection errorCollection = results.Errors;
          lbl.InnerText = "";
          foreach (CompilerError ce in results.Errors)
          {
              lbl.InnerText = lbl.InnerText + "\n" + ce.ToString() + "IsError:" + !ce.IsWarning;
              return;
          }

          string path=results.PathToAssembly;

         Assembly assm= Assembly.LoadFile(path);
         Type typ = assm.GetTypes()[0];
        object d= Activator.CreateInstance(typ);
           // object obj=assm.CreateInstance(typ.Name);

            object returnValue=typ.InvokeMember("kain", BindingFlags.InvokeMethod | BindingFlags.Static |BindingFlags.NonPublic, null, d, null);

            if (lbl.InnerText == "")
            {
                lbl.InnerHtml = "<br><br> <br><br> Your code was successfully executed and dll was created in the path:" + path;
            }
            GC.Collect();
        }
    }
}

Written by pavanarya

August 4, 2012 at 8:39 pm