博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Asp.net Web.config文件读取路径你真的清楚吗?
阅读量:4975 次
发布时间:2019-06-12

本文共 9292 字,大约阅读时间需要 30 分钟。

我们经常都在用ConfigurationManager的AppSettings和ConnectionStrings属性,当一个项目中有很多Web.config时它们的读取顺序究竟是怎么的了?也许我们可以通过实验得出一些结论,但我这里仅从源代码上来分析一下。

无论是ConfigurationManager的AppSettings还是ConnectionStrings属性都在调用方一个共同的方法GetSection。从GetSection方法我们知道他主要是调用IInternalConfigSystem实例的GetSection方法,在这里用实例的GetSection方法之前它调用了一个PrepareConfigSystem方法。一看这个方法名称我们就知道他是为ConfigSystem做准备工作的。而它也是在调用一个EnsureConfigurationSystem方法,这个方法有一句很重要  s_configSystem = newClientConfigurationSystem();但是我们在Web中用的难道就是ClientConfigurationSystem类吗?不一定!让我们 确认一下,在web的项目中,我们添加一下代码:

   FieldInfo s_configSystem = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic);

            object clientConfigurationSystem  = s_configSystem.GetValue(null);

运行结果表明IInternalConfigSystem的实例是一个HttpConfigurationSystem类型。我们大家应该还知道http处理的开始是在HttpRuntime的

public static void ProcessRequest(HttpWorkerRequest wr)->private void ProcessRequestInternal(HttpWorkerRequest wr) ->private void EnsureFirstRequestInit(HttpContext context)->private void FirstRequestInit(HttpContext context)->private static void InitHttpConfiguration()->  HttpConfigurationSystem.EnsureInit(null, true, true).这里我想能说明IInternalConfigSystem的实例类型是HttpConfigurationSystem

internal static void EnsureInit(IConfigMapPath configMapPath, bool listenToFileChanges, bool initComplete){    if (!s_inited)    {        lock (s_initLock)        {            if (!s_inited)            {                s_initComplete = initComplete;                if (configMapPath == null)                {                    configMapPath = IISMapPath.GetInstance();                }                s_configMapPath = configMapPath;                s_configSystem = (IConfigSystem) Activator.CreateInstance(Type.GetType("System.Configuration.Internal.ConfigSystem, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true), true);                object[] hostInitParams = new object[6];                hostInitParams[0] = true;                hostInitParams[1] = s_configMapPath;                hostInitParams[3] = HostingEnvironment.ApplicationVirtualPath;                hostInitParams[4] = HostingEnvironment.SiteNameNoDemand;                hostInitParams[5] = HostingEnvironment.SiteID;                s_configSystem.Init(typeof(WebConfigurationHost), hostInitParams);                s_configRoot = s_configSystem.Root;                s_configHost = (WebConfigurationHost) s_configSystem.Host;                HttpConfigurationSystem internalConfigSystem = new HttpConfigurationSystem();                if (listenToFileChanges)                {                    s_configRoot.ConfigChanged += new InternalConfigEventHandler(internalConfigSystem.OnConfigurationChanged);                }                s_configSettingsFactory = (IInternalConfigSettingsFactory) Activator.CreateInstance(Type.GetType("System.Configuration.Internal.InternalConfigSettingsFactory, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true), true);                s_configSettingsFactory.SetConfigurationSystem(internalConfigSystem, initComplete);                s_httpConfigSystem = internalConfigSystem;                s_inited = true;            }        }    }}

 这段代码主要是实例化了一个HttpConfigurationSystem,InternalConfigSettingsFactory,其中有一句s_configSettingsFactory.SetConfigurationSystem(internalConfigSystem, initComplete)很是重要,让我们来看看InternalConfigSettingsFactory的SetConfigurationSystem方法:

void IInternalConfigSettingsFactory.SetConfigurationSystem(IInternalConfigSystem configSystem, bool initComplete)

    {
        ConfigurationManager.SetConfigurationSystem(configSystem, initComplete);
    }

其中ConfigurationManager.SetConfigurationSystem有这么一句

internal static void SetConfigurationSystem(IInternalConfigSystem configSystem, bool initComplete)

{
        s_configSystem = configSystem;       
}
我想大家现在应该明白为什么IInternalConfigSystem这里是HttpConfigurationSystem了吧。
现在让我们来看看HttpConfigurationSystem的GetSection方法

internal static object GetSection(string sectionName)

{
    HttpContext current = HttpContext.Current;
    if (current != null)
    {
        return current.GetSection(sectionName);
    }
    return GetApplicationSection(sectionName);
}
它实际上是调用的HttpContext 的GetSection方法:

public object GetSection(string sectionName)

{
    if (HttpConfigurationSystem.UseHttpConfigurationSystem)
    {
        return this.GetConfigurationPathData().ConfigRecord.GetSection(sectionName);
    }
    return ConfigurationManager.GetSection(sectionName);
}
最终调用的是CachedPathData的GetVirtualPathData,其调用参数依次是 CachedPathData.GetVirtualPathData(this._request.FilePathObject, false),如果这个有返回值就直接返回,否则继续调用CachedPathData.GetVirtualPathData(this._configurationPath, true)

internal static CachedPathData GetVirtualPathData(VirtualPath virtualPath, bool permitPathsOutsideApp){    if (!HostingEnvironment.IsHosted)    {        return GetRootWebPathData();    }    if (virtualPath != null)    {        virtualPath.FailIfRelativePath();    }    if ((virtualPath != null) && virtualPath.IsWithinAppRoot)    {        return GetConfigPathData(WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(HostingEnvironment.SiteID, virtualPath));    }    if (!permitPathsOutsideApp)    {        throw new ArgumentException(SR.GetString("Cross_app_not_allowed", new object[] { (virtualPath != null) ? virtualPath.VirtualPathString : "null" }));    }    return GetApplicationPathData();}

 这个方法主要是调用GetConfigPathData方法,参数一次是("machine/webroot");(WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(HostingEnvironment.SiteID, virtualPath));));,HostingEnvironment.AppConfigPath,要想知道

(WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(HostingEnvironment.SiteID, virtualPath));));

HostingEnvironment.AppConfigPath

这两个东西在实际的项目中返回的东西可以把以下代码放到web项目中就可以知道它们具体是说明东西了。

            MethodInfo m = Type.GetType("System.Web.Configuration.WebConfigurationHost,System.Web,Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
                .GetMethod("GetConfigPathFromSiteIDAndVPath", BindingFlags.Static | BindingFlags.NonPublic);
            PropertyInfo sitID = typeof(HostingEnvironment).GetProperty("SiteID", BindingFlags.Static | BindingFlags.NonPublic);
            object SitID = sitID.GetValue(null, new object[] { });
            PropertyInfo filePathObject = typeof(HttpRequest).GetProperty("FilePathObject", BindingFlags.NonPublic | BindingFlags.Instance);
            object FilePathObject = filePathObject.GetValue(System.Web.HttpContext.Current.Request, new object[]{});
            object obj = m.Invoke(null, new object[] { SitID, FilePathObject });
            PropertyInfo appConfigPath = typeof(HostingEnvironment).GetProperty("AppConfigPath", BindingFlags.NonPublic | BindingFlags.Static);
            object AppConfigPath = appConfigPath.GetValue(null, new object[] { });

有关CachedPathData 的

private static CachedPathData GetConfigPathData(string configPath)方法具体实现我们及忽略它吧,很是复杂。最主要是这些方法都是内部私有方法,知道了也没多大意义。要想改变web.config的读取路径,理论上很简单就是自己实现一个IInternalConfigSystem子类来修改读取路径不过这个类的修改非常庞大,我们退而求次来改变Request的_filePath变量来实现修改读取路径的方法
具体的实现代码如下:

void MvcApplication_PostMapRequestHandler(object sender, EventArgs e)        {            HttpContextBase context = new HttpContextWrapper(((HttpApplication)sender).Context);            string channelName = context.Request.RequestContext.RouteData.Values["ChannelName"].ToString();            Type typeVirtualPath = Type.GetType("System.Web.VirtualPath,System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");            Type typeCachedPathData = Type.GetType("System.Web.CachedPathData,System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");            MethodInfo Create = typeVirtualPath.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null);            PropertyInfo _filePathObject = typeof(HttpRequest).GetProperty("FilePathObject", BindingFlags.NonPublic | BindingFlags.Instance);            object filePathObject = _filePathObject.GetValue(System.Web.HttpContext.Current.Request, new object[] { });            PropertyInfo _virtualPathString = typeVirtualPath.GetProperty("VirtualPathString");            object virtualPathString = _virtualPathString.GetValue(filePathObject, new object[] { });            string newPathString = virtualPathString.ToString().Replace(channelName, "Views/Channel/" + channelName);            object newVirtualPathString = Create.Invoke(null, new object[] { newPathString });            FieldInfo filePath = typeof(HttpRequest).GetField("_filePath", BindingFlags.NonPublic | BindingFlags.Instance);            filePath.SetValue(System.Web.HttpContext.Current.Request, newVirtualPathString);            object filePathData = typeCachedPathData.GetMethod("GetVirtualPathData", BindingFlags.Static | BindingFlags.NonPublic)                .Invoke(null, new object[] { newVirtualPathString, false });            FieldInfo _filePathData = typeof(HttpContext).GetField("_filePathData", BindingFlags.NonPublic | BindingFlags.Instance);            _filePathData.SetValue(HttpContext.Current, filePathData);            //string aa = ConfigurationManager.AppSettings["TestData"].Trim();        }

 其实个人并不是很建议大家来修改默认的ConfigurationManager来实现该功能。如果需要实现建议大家用WebConfigurationManager来实现。

   var str= WebConfigurationManager.OpenWebConfiguration("/Views/Channel/men/web.config").AppSettings.Settings["TestData"].Value;

看看这个是不是很简单啊。具体的代码

转载于:https://www.cnblogs.com/majiang/archive/2012/11/16/2773480.html

你可能感兴趣的文章
VS 2013 配置份openGL环境
查看>>
修改 CKEditor 超链接的默认协议
查看>>
zoj3795 Grouping --- 良好的沟通,寻找最长的公路
查看>>
【SSH2(理论+实践)】--Hibernate步步(一个)
查看>>
深入浅出JMS(一)——JMS简要
查看>>
JDBC连接MySQL数据库及演示样例
查看>>
小波说雨燕 第三季 构建 swift UI 之 UI组件集-视图集(四)Alert View视图 学习笔记...
查看>>
多线程基础(二)pthread的了解
查看>>
百度SDK的使用第一天
查看>>
python学习笔记3:列表、元组和集合
查看>>
数组的初始化
查看>>
bzoj3156 防御准备
查看>>
Git----查看提交日志
查看>>
XE7/X10.2 Datasnap使用 dbExpress 连接MySQL数据库
查看>>
Eclipse修改编码格式
查看>>
生成器和协程 —— 你想知道的都在这里了
查看>>
初级算法-6.两个数组的交集 II
查看>>
欧拉函数 / 蒙哥马利快速幂 / 容斥
查看>>
Makefile
查看>>
软件开发文档以及项目开发流程理解
查看>>