zoukankan      html  css  js  c++  java
  • asp.net App_Code文件夹相关操作

      最近用到了App_Code文件夹,想要实现动态编译文件的方式,即替换文件夹中的类文件从而达到实时修改代码的效果,类似web.config,网上查到的资料基本都是把文件夹中的类文件修改属性为"编译",这跟我想要的效果不一样,但是不这么做的话在VS中无法调用,想来想去只能使用反射+Expression+缓存的方式来实现了.

      研究了几个小时后搞了一个App_Code帮助类

     假设App_Code文件夹中有这么一个类

    namespace WebTest.App_Code
    {
        public static class TestClass
        {
            public const string TestConst = "testConst";
    
            public readonly static string TestStaticField = "testStaticField";
    
            public static string TestStaticProperty { get { return "testStaticProperty"; } }
    
            public static string TestStaticMethod(string value)
            {
                return value;
            }
    
            public static string TestStaticMethod(string value1, string value2)
            {
                return value1 + value2;
            }
        }
    }

    我想要获取以下内容:

    1.常量TestConst的值

    2.静态字段TestStaticField的值

    3.静态属性TestStaticProperty的值

    4.静态方法TestStaticMethod(string value)的调用结果

    5.静态方法TestStaticMethod(string value1,string value2)的调用结果

    好了,在VS中是无法直接使用的,因为类文件属性未修改为"编译",但是这个类会被动态编译成一个程序集.

    App_Code生成的动态程序集可以通过 System.Web.Compilation.BuildManager.CodeAssemblies 拿到(PreApplicationStart阶段无法获取)

     public static IEnumerable<Assembly> GetApp_CodeAssemblies()
            {
                if (BuildManager.CodeAssemblies != null)
                {
                    foreach (object item in BuildManager.CodeAssemblies)
                    {
                        Assembly assembly;
                        try
                        {
                            assembly = (Assembly)item;
                        }
                        catch
                        {
                            continue;
                        }
                        yield return assembly;
                    }
                }
    
            }
    View Code

    首先我们需要获取类型的Type对象,为了提高性能,代码中使用字典来缓存数据

            static readonly ConcurrentDictionary<string, Type> _typeMap = new ConcurrentDictionary<string, Type>();
    
            static readonly ConcurrentDictionary<Tuple<Type, string>, object> _constMap = new ConcurrentDictionary<Tuple<Type, string>, object>();
    
            static readonly ConcurrentDictionary<Tuple<Type, string>, Func<object>> _staticFieldFactoryMap = new ConcurrentDictionary<Tuple<Type, string>, Func<object>>();
    
            static readonly ConcurrentDictionary<Tuple<Type, string>, Func<object>> _staticPropertyFactoryMap = new ConcurrentDictionary<Tuple<Type, string>, Func<object>>();
    
            static readonly ConcurrentDictionary<Tuple<Type, string, string>, Delegate> _staticMethodFactoryMap = new ConcurrentDictionary<Tuple<Type, string, string>, Delegate>();
    View Code

    为了使用方便,扩展了微软的ConcurrentDictionary类

    namespace System.Web
    {
        internal class ConcurrentDictionary<TKey, TValue> : System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
        {
            public TValue Get(TKey key, Func<TValue> factory)
            {
                TValue value;
                if (!this.TryGetValue(key, out value))
                {
                    value = factory();
                    this.TryAdd(key, value);
                }
                return value;
            }
        }
    }
    View Code
          #region Types
            public static Type[] GetTypes(string fullName)
            {
                return GetTypesInternal(fullName).ToArray();
            }
    
            public static Type GetType(string fullName)
            {            
                return _typeMap.Get(fullName, () => GetTypesInternal(fullName).FirstOrDefault());
            }
    
            static IEnumerable<Type> GetTypesInternal(string fullName)
            {
                foreach (var assembly in Tools.GetApp_CodeAssemblies())
                {
                    var type = assembly.GetTypes().FirstOrDefault(o => o.FullName == fullName);
                    if (type != null)
                    {
                        yield return type;
                    }
                }
            }
            #endregion

    好了,拿到类型了,按顺序解决上面的5个问题

    1.常量值

            /// <summary>
            /// 获取常量值
            /// </summary>
            /// <param name="fullTypeName"></param>
            /// <param name="constName"></param>
            /// <returns></returns>
            public static object GetConstValue(string fullTypeName, string constName)
            {
    
                var type = GetType(fullTypeName);
    
                if (type == null)
                {
                    return null;
                }
    
                return GetConstValue(type, constName);
            }
            /// <summary>
            /// 获取常量值
            /// </summary>
            /// <param name="type"></param>
            /// <param name="constName"></param>
            /// <returns></returns>
            public static object GetConstValue(Type type, string constName)
            {
                if (type == null)
                {
                    throw new ArgumentNullException("type");
                }
                return _constMap.Get(new Tuple<Type, string>(type, constName), () =>
                {
                    var field = type.GetField(constName);
                    if (field == null)
                    {
                        return null;
                    }
                    if ((field.Attributes & System.Reflection.FieldAttributes.Literal) != 0)
                    {
                        return field.GetValue(null);
                    }
                    return null;
                });
            }
    View Code

    2.静态字段值

            /// <summary>
            /// 获取静态字段值
            /// </summary>
            /// <param name="fullTypeName"></param>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public static object GetStaticFieldValue(string fullTypeName, string fieldName)
            {
    
                var type = GetType(fullTypeName);
    
                if (type == null)
                {
                    return null;
                }
    
                return GetStaticFieldValue(type, fieldName);
            }
    
            /// <summary>
            /// 获取静态字段值
            /// </summary>
            /// <param name="type"></param>
            /// <param name="fieldName"></param>
            /// <returns></returns>
            public static object GetStaticFieldValue(Type type, string fieldName)
            {
                if (type == null)
                {
                    throw new ArgumentNullException("type");
                }
    
                var factory = _staticFieldFactoryMap.Get(new Tuple<Type, string>(type, fieldName), () =>
                {
                    var field = type.GetField(fieldName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
                    if (field == null)
                    {
                        return null;
                    }
                    var fieldExpression = Expression.Field(null, field);
                    return Expression.Lambda<Func<object>>(fieldExpression).Compile();
    
                });
    
                return factory == null ? null : factory();
    
            }
    View Code

    3.静态属性值

            /// <summary>
            /// 获取静态属性值
            /// </summary>
            /// <param name="fullTypeName"></param>
            /// <param name="propertyName"></param>
            /// <returns></returns>
            public static object GetStaticPropertyValue(string fullTypeName, string propertyName)
            {
    
                var type = GetType(fullTypeName);
    
                if (type == null)
                {
                    return null;
                }
    
                return GetStaticPropertyValue(type, propertyName);
            }
            /// <summary>
            /// 获取静态属性值
            /// </summary>
            /// <param name="type"></param>
            /// <param name="propertyName"></param>
            /// <returns></returns>
            public static object GetStaticPropertyValue(Type type, string propertyName)
            {
                if (type == null)
                {
                    throw new ArgumentNullException("type");
                }
    
                var factory = _staticPropertyFactoryMap.Get(new Tuple<Type, string>(type, propertyName), () =>
                {
                    var property = type.GetProperty(propertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
                    if (property == null)
                    {
                        return null;
                    }
                    var propertyExpression = Expression.Property(null, property);
                    return Expression.Lambda<Func<object>>(propertyExpression).Compile();
    
                });
    
                return factory == null ? null : factory();
    
            }
    View Code

    4,5.方法返回值

       /// <summary>
            /// 获取静态方法值
            /// </summary>
            /// <param name="fullTypeName"></param>
            /// <param name="methodName"></param>
            /// <param name="args"></param>
            /// <returns></returns>
            public static object GetStaticMethodValue(string fullTypeName, string methodName, params dynamic[] args)
            {
    
                var type = GetType(fullTypeName);
    
                if (type == null)
                {
                    return null;
                }
    
                return GetStaticMethodValue(type, methodName, args);
            }
    
            /// <summary>
            /// 获取静态方法值
            /// </summary>
            /// <param name="type"></param>
            /// <param name="methodName"></param>
            /// <param name="args"></param>
            /// <returns></returns>
            public static object GetStaticMethodValue(Type type, string methodName, params dynamic[] args)
            {
                if (type == null)
                {
                    throw new ArgumentNullException("type");
                }
    
                var types = args.Select(o => (Type)o.GetType()).ToArray();
    
                string argKey = Tools.GetValueFromIEnumerable(types.Select(o => o.FullName));
    
                dynamic factory = _staticMethodFactoryMap.Get(new Tuple<Type, string, string>(type, methodName, argKey), () =>
                {
                    var method = type.GetMethod(methodName, types);
                    if (method == null)
                    {
                        return null;
                    }
                    if (method.ReturnType == null)
                    {
                        return null;
                    }
    
                    var parameters = new ParameterExpression[args.Length];
                    for (int i = 0; i < args.Length; i++)
                    {
                        parameters[i] = Expression.Parameter(args[i].GetType(), "args" + i);
                    }
                    var methodExpression = Expression.Call(null, method, parameters);
                    return Expression.Lambda(methodExpression, parameters).Compile();
                });
    
                if (factory == null)
                {
                    return null;
                }
    
                switch (args.Length)
                {
                    case 0:
                        return factory();
                    case 1:
                        return factory(args[0]);
                    case 2:
                        return factory(args[0], args[1]);
                    case 3:
                        return factory(args[0], args[1], args[2]);
                    case 4:
                        return factory(args[0], args[1], args[2], args[3]);
                    case 5:
                        return factory(args[0], args[1], args[2], args[3], args[4]);
                    case 6:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5]);
                    case 7:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
                    case 8:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
                    case 9:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
                    case 10:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
                    case 11:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
                    case 12:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
                    case 13:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]);
                    case 14:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]);
                    case 15:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14]);
                    case 16:
                        return factory(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]);
                    default:
                        throw new NotImplementedException("参数太多了...");
                }
            }
    View Code

    好了,做个测试:

        public class TestController : Controller
        {
            // GET: Test
            public ActionResult Index()
            {
    
                string testConst = App_CodeHelper.GetConstValue("WebTest.App_Code.TestClass", "TestConst") as string;
    
                string testStaticField = App_CodeHelper.GetStaticFieldValue("WebTest.App_Code.TestClass", "TestStaticField") as string;
    
                string testStaticProperty = App_CodeHelper.GetStaticPropertyValue("WebTest.App_Code.TestClass", "TestStaticProperty") as string;
    
                string testStaticMethod1 = App_CodeHelper.GetStaticMethodValue("WebTest.App_Code.TestClass", "TestStaticMethod", "我是value") as string;
    
                string testStaticMethod2 = App_CodeHelper.GetStaticMethodValue("WebTest.App_Code.TestClass", "TestStaticMethod", "我是value1", "我是value2") as string;
    
                return Json(new
                {
                    testConst,
                    testStaticField,
                    testStaticProperty,
                    testStaticMethod1,
                    testStaticMethod2
                }, JsonRequestBehavior.AllowGet);
            }
        }

    得到结果:

    {"testConst":"testConst","testStaticField":"testStaticField","testStaticProperty":"testStaticProperty","testStaticMethod1":"我是value","testStaticMethod2":"我是value1我是value2"}


    现在我们用记事本打开TestClass类文件,修改代码保存

    namespace WebTest.App_Code
    {
        public static class TestClass
        {
            public const string TestConst = "testConst1";
    
            public readonly static string TestStaticField = "testStaticField1";
    
            public static string TestStaticProperty { get { return "testStaticProperty1"; } }
    
            public static string TestStaticMethod(string value)
            {
                return value+"1";
            }
    
            public static string TestStaticMethod(string value1, string value2)
            {
                return value1 +"+"+ value2;
            }
        }
    }

    此时应用程序重启,再次访问,结果变成了:

    {"testConst":"testConst1","testStaticField":"testStaticField1","testStaticProperty":"testStaticProperty1","testStaticMethod1":"我是value1","testStaticMethod2":"我是value1+我是value2"}


    效果还是不错的,当然如果只是使用字段属性的话完全可以使用web.config,但是动态调用方法的话还是可以派上用场的!!!
  • 相关阅读:
    引用 AspNetCoreRateLimit => StatusCode cannot be set because the response has already started.
    Sublime Json 格式化
    gitlab 建立本地仓库
    R语言 启动报错 *** glibc detected *** /usr/lib64/R/bin/exec/R: free(): invalid next size (fast): 0x000000000263a420 *** 错误 解决方案
    范数
    SparkR-Install
    R语言扩展包dplyr——数据清洗和整理
    R语言与机器学习学习笔记
    sparkR原理
    data.frame类型数据如何将第一列值替换为行号
  • 原文地址:https://www.cnblogs.com/pokemon/p/6137764.html
Copyright © 2011-2022 走看看