【问题标题】:Config files and retrieving in Azure-Functions在 Azure-Functions 中配置文件和检索
【发布时间】:2017-09-08 20:01:32
【问题描述】:

我一直在尝试使用 Azure-Functions 中的 .config 文件。

如果我写这个函数

using System;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;


namespace GranadaCoder.AzurePoc.AzureFunctionsOne
{
    public static class AppSettingsTestOne
    {
        [FunctionName("AppSettingsTestOneFunctionName")]
        public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
        {

            try
            {

                string rootDirectory = string.Empty;
                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HOME")))
                {
                    /* running in azure */
                    rootDirectory = Environment.GetEnvironmentVariable("HOME") + "\\site\\wwwroot";
                }
                else
                {
                    /* in visual studio, local debugging */
                    rootDirectory = ".";
                }
                string path = rootDirectory + @"\CustomConfigFiles\CustomAppSettings.config";

                if (!System.IO.File.Exists(path))
                {
                    throw new System.IO.FileNotFoundException(string.Format("NOT FOUND!!! ('{0}')", path));
                }
                else
                {
                    log.Info(string.Format("File exists='{0}'", path));
                }

                ExeConfigurationFileMap map = new ExeConfigurationFileMap { ExeConfigFilename = path };
                Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

                Configuration fileConfig = ConfigurationManager.OpenExeConfiguration(path); /* does NOT work */
                string val1 = config.AppSettings.Settings["KeyOne"].Value;
                string val2 = config.AppSettings.Settings["KeyTwo"].Value;
                string val3 = config.AppSettings.Settings["KeyThree"].Value;

                string msg = string.Join(",", val1, val2, val3);

                return req.CreateResponse(HttpStatusCode.OK, msg);
            }
            catch (Exception ex)
            {
                string errorMsg = ex.Message; //  ExceptionHelper.GenerateFullFlatMessage(ex);
                log.Error(errorMsg);
                return req.CreateResponse(HttpStatusCode.BadRequest, errorMsg);
            }
        }
    }
}

使用此 .config 文件 (CustomAppSettings.config)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="KeyOne" value="ValueOne" />
    <add key="KeyTwo" value="ValueTwo" />
    <add key="KeyThree" value="ValueThree" />
  </appSettings>
</configuration>

它按预期工作。

如果我使用这个功能:

using System;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml;

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;


namespace GranadaCoder.AzurePoc.AzureFunctionsOne
{
    public static class NameValuePairAppSettingsTest
    {
        [FunctionName("NameValuePairAppSettingsTestFunctionName")]
        public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
        {

            try
            {
                string rootDirectory = string.Empty;
                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HOME")))
                {
                    /* running in azure */
                    rootDirectory = Environment.GetEnvironmentVariable("HOME") + "\\site\\wwwroot";
                }
                else
                {
                    /* in visual studio, local debugging */
                    rootDirectory = ".";
                }
                string path = rootDirectory + @"\CustomConfigFiles\NameValuePairSettings.config";


                if (!System.IO.File.Exists(path))
                {
                    throw new System.IO.FileNotFoundException(string.Format("NOT FOUND!!! ('{0}')", path));
                }
                else
                {
                    log.Info(string.Format("file exists='{0}'", path));
                }

                ExeConfigurationFileMap map = new ExeConfigurationFileMap { ExeConfigFilename = path };
                Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

                //NameValueCollection nvc = (NameValueCollection)config.GetSection("myLittleArea"); /* does not work */

                ConfigurationSection myParamsSection = config.GetSection("myLittleArea");
                /* see https://stackoverflow.com/questions/13825323/how-do-i-get-the-values-from-a-configsection-defined-as-namevaluesectionhandler */
                string myParamsSectionRawXml = myParamsSection.SectionInformation.GetRawXml();
                XmlDocument sectionXmlDoc = new XmlDocument();
                sectionXmlDoc.Load(new StringReader(myParamsSectionRawXml));
                NameValueSectionHandler handler = new NameValueSectionHandler();
                NameValueCollection nvc = handler.Create(null, null, sectionXmlDoc.DocumentElement) as NameValueCollection;

                var items = nvc.AllKeys.SelectMany(nvc.GetValues, (k, v) => new { key = k, value = v });
                ////////foreach (var item in items)
                ////////{
                ////////    Console.WriteLine("{0} {1}", item.key, item.value);
                ////////}

                string msg = string.Join(",", items.ToList());

                return req.CreateResponse(HttpStatusCode.OK, msg);
            }
            catch (Exception ex)
            {
                string errorMsg = ex.Message; //  ExceptionHelper.GenerateFullFlatMessage(ex);
                log.Error(errorMsg);
                return req.CreateResponse(HttpStatusCode.BadRequest, errorMsg);
            }
        }
    }
}

使用此 .config 文件 (NameValuePairSettings.config)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="myLittleArea" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </configSections>

  <myLittleArea>
    <add key="color" value="red"/>
    <add key="street" value="main"/>
    <add key="month" value="july"/>
    <add key="candy" value="snickers"/>
  </myLittleArea>

</configuration>

一切正常。

(鼓声)。

如果我创建自定义配置部分。

using System.Configuration;

namespace GranadaCoder.AzurePoc.ConfigurationLibrary.MyCustomConfigurationSettings
{
    public static class MyCustomConfigurationSettingsConfigurationRetriever
    {
        public static readonly string ConfigurationSectionName = "MyCustomConfigurationSettingsConfigurationSectionName";

        /*
        public static MyCustomConfigurationSettingsConfigurationSection GetMyCustomConfigurationSettings()
        {
            MyCustomConfigurationSettingsConfigurationSection returnSection = (MyCustomConfigurationSettingsConfigurationSection)ConfigurationManager.GetSection(ConfigurationSectionName);
            if (returnSection != null)
            {
                return returnSection;
            }

            return null;
        }
        */

        public static MyCustomConfigurationSettingsConfigurationSection GetMyCustomConfigurationSettings(System.Configuration.Configuration cfg)
        {
            MyCustomConfigurationSettingsConfigurationSection returnSection = (MyCustomConfigurationSettingsConfigurationSection)cfg.GetSection(ConfigurationSectionName);
            if (returnSection != null)
            {
                return returnSection;
            }

            return null;
        }
    }
}

using System.Configuration;

namespace GranadaCoder.AzurePoc.ConfigurationLibrary.MyCustomConfigurationSettings
{
    public class MyCustomConfigurationSettingsConfigurationSection : ConfigurationSection
    {
        private const string FavoriteNumberPropertyName = "FavoriteNumber";
        private const string FavoriteColorPropertyName = "FavoriteColor";

        [ConfigurationProperty(FavoriteNumberPropertyName, IsRequired = true, DefaultValue = 100)]
        public int FavoriteNumber
        {
            get
            {
                return (int)this[FavoriteNumberPropertyName];
            }
        }

        [ConfigurationProperty(FavoriteColorPropertyName, IsRequired = true, DefaultValue = ",")]
        public string FavoriteColor
        {
            get
            {
                return (string)this[FavoriteColorPropertyName];
            }
        }
    }
}

和 .config (MyCustomConfigurationSettings.config)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name ="MyCustomConfigurationSettingsConfigurationSectionName" type="GranadaCoder.AzurePoc.ConfigurationLibrary.MyCustomConfigurationSettings.MyCustomConfigurationSettingsConfigurationSection, GranadaCoder.AzurePoc.ConfigurationLibrary" />
  </configSections>
  <MyCustomConfigurationSettingsConfigurationSectionName
    FavoriteNumber="333"
    FavoriteColor="Green"
  >
  </MyCustomConfigurationSettingsConfigurationSectionName>
</configuration>

和天蓝色的功能代码

using System;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

using GranadaCoder.AzurePoc.ConfigurationLibrary.MyCustomConfigurationSettings;



namespace GranadaCoder.AzurePoc.AzureFunctionsOne
{
    public static class CustomConfigurationTest
    {
        [FunctionName("CustomConfigurationTestFunctionName")]
        public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
        {
            try
            {
                string rootDirectory = string.Empty;
                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HOME")))
                {
                    /* running in azure */
                    rootDirectory = Environment.GetEnvironmentVariable("HOME") + "\\site\\wwwroot";
                }
                else
                {
                    /* in visual studio, local debugging */
                    rootDirectory = ".";
                }
                string path = rootDirectory + @"\CustomConfigFiles\MyCustomConfigurationSettings.config";

                log.Info(string.Format("CustomConfigurationTestFunctionName HostingEnvironment.ApplicationPhysicalPath='{0}'", System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath));

                if (!System.IO.File.Exists(path))
                {
                    throw new System.IO.FileNotFoundException(string.Format("NOT FOUND!!! ('{0}')", path));
                }
                else
                {
                    log.Info(string.Format("File exists='{0}'", path));
                }

                ExeConfigurationFileMap map = new ExeConfigurationFileMap { ExeConfigFilename = path };
                Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

                MyCustomConfigurationSettingsConfigurationSection customSection = MyCustomConfigurationSettingsConfigurationRetriever.GetMyCustomConfigurationSettings(config);

                string msg = string.Join(",", customSection.FavoriteNumber.ToString(), customSection.FavoriteColor);

                return req.CreateResponse(HttpStatusCode.OK, msg);
            }
            catch (Exception ex)
            {
                string errorMsg = ex.Message; //  ExceptionHelper.GenerateFullFlatMessage(ex);
                log.Error(errorMsg);
                return req.CreateResponse(HttpStatusCode.BadRequest, errorMsg);
            }
        }
    }
}

上述方法不起作用。

我收到一个错误

“为 MyCustomConfigurationSettingsConfigurationSectionName 创建配置节处理程序时出错:无法加载文件或程序集“GranadaCoder.AzurePoc.ConfigurationLibrary”或其依赖项之一。系统找不到指定的文件。(C:\blah\blah\ blah\bin\Debug\net461\CustomConfigFiles\MyCustomConfigurationSettings.config 第 4 行)"

文件在那里(见图)

知道为什么自定义配置不起作用吗?

【问题讨论】:

  • 您为什么决定使用自定义配置实现而不是使用 ConfigurationManager 的“正常”方法?使用默认方法时,您可以利用 Azure 和发布管理(任何其他部署系统)的功能。可以在这个 SO 问题中找到有关配置函数的更多信息:stackoverflow.com/a/45681977/352640 但是,如果您有正当理由不使用它,请忽略此评论。我仍然很好奇你为什么要这样实现它。

标签: azure azure-functions azure-functions-runtime


【解决方案1】:

在Azure Function中打印出当前域的BaseDirectory后,发现该函数是由fun.exe运行的。它将在“AppData\Local\Azure.Functions.Cli\1.0.1\”文件夹中查找程序集。将“GranadaCoder.AzurePoc.ConfigurationLibrary”复制到文件夹后,该功能将正常工作。

代码:

string friendlyName = AppDomain.CurrentDomain.FriendlyName;
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;

输出:

BaseDirectory = "C:\\Users\\myusername\\AppData\\Local\\Azure.Functions.Cli\\1.0.1\\"
FriendlyName = "func.exe"

【讨论】:

  • 你解开了这个谜。我不喜欢这可能是它的工作方式......(杀死 xcopy 部署场景)............但它现在可以工作了。您必须使文件保持最新......否则您会收到此错误。 (下一条评论)
  • [A]GranadaCoder.AzurePoc.ConfigurationLibrary.MyCustomConfigurationSettings.MyCustomConfigurationSettingsConfigurationSection 无法转换为 [B]GranadaCoder.AzurePoc.ConfigurationLibrary.MyCustomConfigurationSettings.MyCustomConfigurationSettingsConfigurationSection。
  • 类型 A 源自 'GranadaCoder.AzurePoc.ConfigurationLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 在位置 'C:\Users\MyUserName\AppData 的上下文'Default' \Local\Azure.Functions.Cli\1.0.0-beta.99\GranadaCoder.AzurePoc.ConfigurationLibrary.dll'。
  • 类型 B 源自 'GranadaCoder.AzurePoc.ConfigurationLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 在位置 'C:\MyDeployment\GranadaCoder.AzurePoc' 的上下文 'LoadFrom' .AzureFunctionsOne\bin\Debug\net461\GranadaCoder.AzurePoc.ConfigurationLibrary.dll'。
  • 澄清我之前的声明。包含“逻辑”(解释自定义配置)的 .dll 必须位于 func.exe 所在的目录中。但是设置本身可以与函数 .dll 相辅相成。
【解决方案2】:

Azure 函数仅支持 app.config 的有限部分。它允许在从 VS 运行功能时将应用程序设置和连接保存在 local.settings.json 中。它不支持此 json 文件中 system.serviceModel 下的 WCF 端点设置。我在 AzureFunction 中有一个 dll 库引用,它在内部调用 WCF api。

我发现奇怪的是,当我运行 Azure 函数时,它会在 cli 路径 (C:\Users\>\AppData\Local\AzureFunctionsTools\Releases\1.6 .0\cli\func.exe.config)。我将我的 xml 配置层次结构 (system.serviceModel) 添加到此配置文件中,它运行良好,选择了我的 WCF 端点来运行服务。虽然在使用 log4net 配置方面遇到了困难,但很适合运行 API。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 2019-10-20
    • 2022-07-06
    • 2019-10-06
    • 2019-03-13
    • 2021-12-08
    • 1970-01-01
    相关资源
    最近更新 更多