Azure函数结构来自Git存储库

时间:2016-10-14 14:38:18

标签: azure azure-functions

我有一个C#类进行地址查找。我想将其公开为Azure功能。我一直在浏览文档,但看不到我怎么做/是否可以执行以下操作:

  1. 我在Team Services中有一个Git存储库,其中包含AddressLookup的类库。我的功能可以参考这个项目吗?
  2. 如果我查看网站的文件夹结构,我可以看到它已经复制了Git存储库中的所有源文件,我是否可以通过它来构建解决方案,或者只是简单地提取所有文件?
  3. 我在解决方案中的哪个位置?我是否创建了该函数名称的解决方案文件夹并将相关文件放在那里?
  4. My AddressLookup类返回在类库中定义的对象。该功能是否能够使用并返回?
  5. 由于

    亚历

2 个答案:

答案 0 :(得分:1)

第一季度的后续行动:您是否尝试设置CI?要与Azure Functions持续集成,可以参考以下内容:

https://azure.microsoft.com/en-us/documentation/articles/functions-continuous-deployment/#setting-up-continuous-deployment

http://flgmwt.github.io/azure/azure-functions/c-sharp/2016/04/04/azure-fns-with-ci.html

- 更新10/17 -

特定于团队服务,以下是步骤:

  1. 确保您的VSTS帐户已链接到Azure订阅。按照此article中的说明操作。

  2. 导航到功能应用的功能门户,然后点击功能应用设置 - >配置持续集成

  3. 部署刀片中,单击设置并配置部署源信息(请参阅下面的示例快照)。点击确定按钮。等待同步成功。关闭部署刀片。

  4. enter image description here

    1. 给它一分钟并刷新您的功能门户会话。您现在应该看到添加到功能站点的功能。下面的快照是我的 AddressLookup 功能,该功能已从我的Team Services项目中同步,名为 MyFirstProject
    2. 请注意代码编辑器上方的免责声明消息。如果您为函数连接CI,则无法在函数门户中对其进行编辑。由于此特定示例需要请求正文,因此您需要使用Postman进行测试。

      enter image description here

      - 更新结束10/17 -

      回答Q2: 这是一个很好的文档,描述了Azure Functions的文件夹结构: https://azure.microsoft.com/en-us/documentation/articles/functions-reference/

      我还建议特定于Azure函数的C#开发的后续文档: https://azure.microsoft.com/en-us/documentation/articles/functions-reference-csharp/

      回答Q3&问题4:我将尝试通过提供示例实现来回答这些问题。我没有关于AddressLookup库实现的任何上下文,但是,为了提供一个示例,我将采取一个疯狂的飞跃,并假设它是一个将执行一些地理编码操作的库。再次假设您要在HTTP触发的函数中使用此库,您可以首先生成AddressLookup.dll,然后将其上传到函数内的bin文件夹。然后,您可以从Function脚本中引用该DLL。

      例如,使用此article作为参考,我在Visual Studio中生成了一个具有以下实现的AddressLookup.dll库。此DLL将作为AddressLookup库的代理,以便我可以演示如何在函数中使用它。

      using System;
      using System.Globalization;
      using System.IO;
      using System.Linq;
      using System.Net;
      using System.Web;
      using System.Xml.Linq;
      
      namespace AddressLookup
      {
          public class GeoLocation
          {
              public double Longitude { get; set; }
      
              public double Latitude { get; set; }
          }
      
          public class GeoCoder
          {
              private const string geoCodeLookupUrlPattern =
                  "https://maps.googleapis.com/maps/api/geocode/xml?address={0}&key={1}";
      
              private const string addressLookupUrlPattern =
                  "https://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&key={2}";
      
              private string _apiKey = null;
              public GeoCoder(string apiKey)
              {
                  if (string.IsNullOrEmpty(apiKey))
                  {
                      throw new ArgumentNullException("apiKey");
                  }
      
                  _apiKey = apiKey;
              }
      
              public GeoLocation GetGeoLocation(string address)
              {
                  GeoLocation loc = null;
                  string encodedAddress = HttpUtility.UrlEncode(address);
                  string url = string.Format(geoCodeLookupUrlPattern, encodedAddress, _apiKey);
      
                  WebRequest request = WebRequest.Create(url);
      
                  using (WebResponse response = request.GetResponse())
                  {
                      using (Stream stream = response.GetResponseStream())
                      {
                          if (stream != null)
                          {
                              XDocument document = XDocument.Load(new StreamReader(stream));
      
                              XElement longitudeElement = document.Descendants("lng").FirstOrDefault();
                              XElement latitudeElement = document.Descendants("lat").FirstOrDefault();
      
                              if (longitudeElement != null && latitudeElement != null)
                              {
                                  loc = new GeoLocation
                                  {
                                      Longitude = Double.Parse(longitudeElement.Value, CultureInfo.InvariantCulture),
                                      Latitude = Double.Parse(latitudeElement.Value, CultureInfo.InvariantCulture)
                                  };
                              }
                          }
                      }
                  }
      
                  return loc;
              }
      
              public string GetAddress(GeoLocation loc)
              {
                  string address = null;
                  string url = string.Format(addressLookupUrlPattern, loc.Latitude, loc.Longitude, _apiKey);
      
                  WebRequest request = WebRequest.Create(url);
      
                  using (WebResponse response = request.GetResponse())
                  {
                      using (Stream stream = response.GetResponseStream())
                      {
                          if (stream != null)
                          {
                              XDocument document = XDocument.Load(new StreamReader(stream));
                              XElement element = document.Descendants("formatted_address").FirstOrDefault();
                              if (element != null)
                              {
                                  address = element.Value;
                              }
                          }
                      }
                  }
      
                  return address;
              }
          }
      }
      

      现在,让我们通过执行以下步骤来创建HTTP触发函数:

      1. 转到Functions Portal。使用 HTTP创建一个函数 触发器 - C#模板。
      2. 填写姓名(例如AddressLookup)和授权级别(例如Anonymous)。您现在应该看到一个名为AddressLookup的函数,该函数使用一些预先填充的代码创建。
      3. 在左侧窗格中,点击功能应用设置按钮。
      4. 可选:点击配置应用设置。在"应用程序设置"部分,使用您的API密钥为密钥GoogleMapsAPIKey添加值,然后单击保存按钮。 注意:如果您跳过此步骤,则需要稍后在功能代码中对密钥进行硬编码。
      5. 接下来,使用Kudu控制台上传您的DLL。点击转到Kudu 按钮。这将启动一个新的浏览器窗口 使用 cmd 控制台。键入以下内容以导航到您的 功能目录,

        cd site\wwwroot\AddressLookup

      6. 通过在命令提示符下键入bin创建mkdir bin文件夹,如下所示,

        enter image description here

        双击bin文件夹和upload(请参阅"添加文件")AddressLookup.dll到文件夹中。当你完成后,你应该在下面写一个类似的快照,

        enter image description here

      7. 返回功能门户。在“功能”编辑器的“代码”部分底部,单击查看文件。您现在应该看到新创建的bin文件夹,如下所示,

        enter image description here

      8. 使用以下代码替换预先填充的Function脚本的内容

        #r "AddressLookup.dll"
        
        using System;
        using AddressLookup;
        using System.Net;
        
        public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
        {
            log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
        
            // Reading environment variable from App Settings, replace with hardcoded value if not using App settings
            string apiKey = System.Environment.GetEnvironmentVariable("GoogleMapsAPIKey", EnvironmentVariableTarget.Process);
        
            // Get request body
            dynamic data = await req.Content.ReadAsAsync<object>();
            string address = data?.address;
            string name = data?.name;
        
            GeoCoder geoCoder = new GeoCoder(apiKey);
            GeoLocation loc = geoCoder.GetGeoLocation(address);
            string formattedAddress = geoCoder.GetAddress(loc);
        
            HttpResponseMessage message = null;
            if (name == null)
            {
                message = req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name in the request body");
            }
            else
            {
                var msg = $"Hello {name}. Lon: '{loc.Longitude}', Lat: '{loc.Latitude}', Formatted address: '{formattedAddress}'"; 
                message = req.CreateResponse(HttpStatusCode.OK, msg);
            }
        
            return message;
        }
        
        1. 点击保存按钮。
        2. 在&#34; Run&#34;部分,提供以下请求正文,

          { "name": "Azure", "address": "One Microsoft Way Redmond WA 98052" }

        3. 点击运行按钮。

        4. 您应该会看到一些与以下内容类似的日志条目
        5. 2016-10-15T03:54:31.538 C# HTTP trigger function processed a request. RequestUri=https://myfunction.azurewebsites.net/api/addresslookup 2016-10-15T03:54:31.773 Function completed (Success, Id=e4308c0f-a615-4d43-8b16-3a6afc017f73)

          以及以下HTTP响应消息

          "Hello Azure. Lon: '-122.1283833', Lat: '47.6393225', Formatted address: '1 Microsoft Way, Redmond, WA 98052, USA'"

          由于这是一个HTTP触发的函数,您还可以使用Postman测试您的函数。见下面的快照,

          enter image description here

          如果您在步骤5中上传自己的DLL并编辑功能代码以调用您的库,则该功能也应该正常工作。

答案 1 :(得分:0)

您要引用的程序集是否已冻结,或者您是否要查看更新?如果您不想看到更新,请参阅Ling Toh的答案。

但是如果你想在程序集更新时看到更新:

将您的功能链接到某种形式的持续交付。 official documentation解释了如何执行此操作。目前,您似乎需要一个单独的git存储库,VSTS项目(或其他)来轻松完成此任务。 (可以在Kudu中编辑部署过程,但如果可能的话,我会避免这种情况)。

函数项目应该只包含函数代码本身。所以它应该包含类似跟随的内容:

global.json
host.json
packages.config
Web.config
function1/
function1/run.csx
function1/project.json
function1/function.json

你应该用你的函数名替换function1。

一旦您将其配置为推送到您的功能主机,您就会大部分时间到达您想要的位置。接下来,添加一个function1 / run子目录,放置yourAssembly.dll。这应该在成功构建装配项目时自动复制到此处。我没有VSTS的经验来确切知道最好的方法,所以你可能需要提出另一个问题。

您现在已将组件放置在正确的位置。现在,您可以通过将程序集引用行添加到run.csx的顶部来引用它:

#r "yourAssembly.dll"

请注意,所有引用都必须在run.csx顶部的其他所有之前。所以你可以把它放在其他引用之后,但它必须在任何其他之前,包括加载规范。

请注意,对于自定义程序集,您包含.dll并引用该文件,而对于默认情况下未引用的框架程序集,您不必

在一个理想的世界里,这就足够了。

但是,如果仅在更新project.json,run.csx或function.json的情况下更新程序集,则函数不会触发重建。因此,作为此过程的一部分,我查看文件的末尾并添加或删除空行。它必须毫无意义(因此你不会改变重要的东西),但足以让你的版本控制工具认为文件已经改变了。显然,如果您还对文件进行了其他更改,则无需执行此步骤。

如果您正在使用git,那么您现在可以提交并推送更改。函数将看到该函数已更改,并重新编译。您应该在函数本身的日志窗格中看到这一点。

请注意,如果您有两个使用相同从属程序集的函数,则需要将其复制到两个函数文件夹中;这不能分享。