如何使用Azure函数

422 阅读8分钟

开始使用Azure功能

Azure函数是一种云原生设计策略,允许提供和执行一段代码,而不需要网络服务器或服务器基础设施设置。

C#、Java、JavaScript、TypeScript和Python只是与Azure函数集成的几种语言。

Azure函数是一个无服务器计算平台,它简化了云中少量代码或函数的执行。因此,它提高了我们的开发效率。

只编写手头任务所需的代码,而不考虑程序的其他部分或操作所需的基础设施。

本文解释了什么是Azure函数以及如何在C#编程语言中利用它们。

优点

  • Azure函数很简单,不需要服务器。
  • 编写和部署Azure函数要容易得多。
  • Azure函数的执行是在事件发生时启动的。
  • Azure函数不需要任何基础设施,也不需要任何维护。
  • 使用Azure界面和浏览器,我们可以创建、测试和部署Azure函数。
  • 对Azure功能的升级很简单,对网站的其他元素没有影响。
  • Azure函数使用行业标准与其他API、数据库和库集成。
  • 因为Azure函数是按需计算的,所以当执行请求的数量增加时,它们会扩大规模,而当请求的数量减少时,它们会缩小规模。

前提条件

  • 具备使用Visual studio 2019和SQL数据库创建器的背景信息。
  • 下载[Visual studio 2019]以编译Csharp代码。
  • 有一些关于SQL数据库和连接的知识。
  • 为了执行SQL命令,使用SQL编译器。对于我的情况,我使用[oracle终端在线]来执行命令。

如何设置Azure函数

为了建立Azure函数,我们将使用Visual Studio。在Visual Studio中,打开Blazor应用程序并创建一个新项目。然后,在项目模板页面上选择Azure函数。

Output of the setup

选择Azure函数模板后,点击下一步。你需要为你的功能应用命名,并为Visual Studio项目选择一个操作位置。

This what you will see

下面的图片描述了Visual Studio中对Azure函数应用的众多触发器。

Trigger of the Visual Studio

我们可以看到,每个触发器都有不同的作用。我们将利用HTTP触发器,它在发送HTTP请求的任何时候都会触发。点击创建按钮来创建应用程序。

下面是我们的函数的完整代码的一个例子

using System;    
using System.IO;    
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;    
using Microsoft.Azure.WebJobs;    
using Microsoft.Azure.WebJobs.Extensions.Http;      
using Microsoft.Extensions.Logging; 
using Microsoft.AspNetCore.Http;   
using Newtonsoft.Json;    
namespace HelloFunction {    
    public static class Function1 {    
        [FunctionName("Function1")]    
        public static async Task < IActionResult > Run(    
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) {  // HTTP trigger is executed whenever we make an HTTP request. 
            log.LogInformation("C# HTTP trigger function processed a request."); //This trigger causes the function to run.    
            string name = req.Query["name"];    
            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();    
            dynamic data = JsonConvert.DeserializeObject(requestBody);    
            name = name ?? data?.name;    
            string responseMessage = string.IsNullOrEmpty(name) ?    
            return new OkObjectResult(responseMessage);    
        }    
    }    
} 

上述代码中的每个触发器都提示函数的运行。一个函数只会有一个触发器,并且只有一个目的。例如,当我们发起一个HTTP请求时,HTTP触发器将执行,导致我们的函数运行。

输出。

This is the output

实体模型和数据库模式

数据库模式代表了一个关系数据库的全部或部分的逻辑设置。我们可以直观地表示数据库模式,也可以将其作为一系列控制数据库的公式,即integrity constraints

完整性约束是限制数据库潜在状态的机制。例如,如果我们考虑一个数据库的雇员,我们不希望有两行是同一个人。因此,根据完整性约束,employee ID在表employee的所有行中必须是唯一的。

术语entity data model ,指的是定义数据结构的概念,无论其存储方式如何。该模型使用三个基本概念描述数据结构:实体类型、关联类型和属性。

下面是雇员表模式的例子。

CREATE TABLE Employee 
(
    Id int IDENTITY (1,1) PRIMARY KEY,
    Name nvarchar(60)NOT NULL,
    Designation nvarchar(60) NOT NULL,
    Town nvarchar(60) NOT NUll
);

在上面的代码中,我们在将要使用的数据库中为雇员创建一个表。

output of the setup

创建一个文件夹,并将其命名为My_Model。在这个文件夹中,创建一个名为Employee 的类。你可以使用一些属性来使你的实现更简单。

下面是一个例子。

namespace API_EFCore_AzureFunctions.My_Model
 {
       public class Employee //creating our class (employee)
    {
        public int IdNumber {get;set;}
        public string Name {get;set;}
        public string Apointment { get; set;}
        public string Town {get; set;}

    }
 }

之后,我们将不得不把DatabaseContext 类添加到我们的项目中。DatabaseContext 允许我们使用应用程序来访问由我们的模型生成的数据库表。

创建一个名为AppDatabaseContext 的新类,并添加下面的代码片段。

using Microsoft. Entity FrameworkCore;

namespace API_EFCore_AzureFunctions.model
{
    public class AppDataBaseContex:DataBaseContext //creating app databasecontext to define our Databasecontext.
    {
          public class AppDataBasebContex(DataBaseContextOptions<AppDataBaseContext>options)
          :base(options)
        {

        }
         public DataBase<Employee> Employee {get;set;}

    }
}

上面的代码解释了我们如何创建数据库上下文以访问数据库中的表。

设置连接

要在Solution Explorer ,你需要右键单击Reference 或一个项目,然后选择管理NuGet包。

如下图所示,我们将使用Nuget包管理器或包管理器控制台安装所需的包。

output of the setup

Visual studio在浏览选项卡中显示来自选定来源的包。使用搜索框来搜索特定的包。安装按钮以及版本选择下拉菜单应该被启用。

初始化依赖注入

为了给我们的函数应用程序设置依赖注入,我们使用Assembly的FunctionsStartup 功能来定义一个启动类,该类将在函数应用程序启动时运行。在这个派生于Functions Startup的类中,我们将重写Configure函数。

通过在服务中注册一个DbContext ,我们可以从配置中获得SQL连接字符串,并将AppDbContext 注入我们的方法中。创建一个名为Startup.cs 的类。


 using API_EFCore_AzureFunctions.Model;
 using Microsoft.Azure.Functions.Extensions.DependencyInjection;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(API_EFCore_AzureFunctions.Startup))] // Indication of a startup class used to run tje function app start.

 namespace API_EFCore_AzureFunctions
{
   public class Startup : FunctionsStartup // Integrates injection's dependency 
   {
        public override void Configure(IFunctionsHostBuilder builder)// Configuration retrives the sql connection.
        {
            string connectionString = "Data Source=Server Name;Integrated   Security=true;Database=Database Name";
            builder.Services.AddDataBaseContext<AppDataBaseContext>(
                options => SqlServerDataBaseContextOptionsExtensions.UseSqlServer(options, connectionString));
        }
   }
}

代码显示了我们如何在app函数中设置依赖注入,我们将使用汇编上的函数启动属性来表示一个将运行app启动函数的类。

将DbContext注入到一个函数中

因为有了依赖注入,我们现在可以在类中声明我们的函数,并将依赖注入到其构造函数中。首先,打开Function1.cs 文件,注入我们的依赖关系。

我们将打开我们的函数,如下图所示。

#region Property
private readonly AppDataBaseContext _appDataBaseContext;
#endregion

#region Constructor
public Function one (AppDataBaseContext appDataBaseContext)
{
    _appDataBaseContext = appDataBaseContext;
}
#endregion

我们将使用上面的代码来注入类的依赖关系。

实现函数

在下面的例子中,我们将在实现函数时使用五个函数。

  1. CreateEmployee - 将雇员信息保存到数据库中。
  2. GetEmployees - 从数据库中获取所有雇员的列表。
  3. GetEmployeebyId - 使用雇员的ID获得雇员记录。
  4. UpdateEmployee - 更新数据库中的雇员信息。
  5. DeleteEmployee - 删除数据库中的雇员记录。

1.1.CreateEmployee

#region Create Employee
       
  [FunctionName("CreateEmployee")] // Here we create a new function employee
    public async Task<IActionResult> CreateEmployee(
    [HttpTrigger(AuthorizationLevel.Anonymous, "save", Route = Route +"/Uplode")]
         HttpRequest req, ILogger log)
        {

           log.LogInformation("How we can get a new  employee list"); //Saves employee information in the database
           variable requestBody = await new StreamReader(req.Body).ReadToEndAsy();
           variable input = JsonConvert.DeserializeObject<Employee>(requestBody);
           variable employee = new Employee
            {

             Name = input.Name, Designation = input.Designation,City= input.City 
                   };
                       await _appDataBaseContext.Employee.AddAsync(employee);
                       await _appDataBaseContext.SaveChangesAsync();
                       return new OkObjectResult(new
            {
                    Message = "Sucessfull ,our record is saved", Data = employee
                   });
       }
       #endregion
       

上述代码在创建的数据库中添加新的雇员。

2.GetEmployee

#region Function Get Employees
       
        [FunctionName("All employees are got")]
        public async Task<IActionResult> GetEmployees(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
          HttpRequest req, ILogger log)
        {
            try //This checks for any exceptions that may occur.
              {
                log.LogInformation("Getting Employee list items");
                return new OkObjectResult(await _appDataBaseContext.Employee.ToListAsync());
                }
            catch (System.Exception) // Handles any exceptions that may occur.
              {
                throw;
            }

        }
        #endregion

行代码[FunctionName("GetAllEmployee")] ,用于为函数属性添加一个名称

代码为[public async Task<IActionResult> GetAllEmployees] 的行用于定义一个函数的方法

代码为[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] 的一行被用作HTTP触发器的属性。

  • 授权级别:授权密钥确保你的HTTP触发器是Azure函数。有三种类型的授权级别。

  • 匿名:不需要密钥

  • 函数:你将需要一个特殊的功能密钥。如果没有提供值,这就是默认值。

  • 管理员:你将需要一个主密钥。

  • 路由:它指定了端点的路由模板。API/FunctionName> 是路由的默认值。

  • 方法:这是为函数定义HTTP动词的地方。

 {
     try
       {
          log.LogInformation("Getting Employee list items");
           return new OkObjectResult(await _appDataBaseContext.Employee.ToListAsync());
            }
            catch (System.Exception)
         {
                throw;
     }
            

上面的代码是getEmployee 函数的一部分,它添加了一个try-catch块来管理异常,并从数据库中检索所有的雇员信息。

3.GetEmloyeebyld

#region Get Employee Based on Employee Id
       // Get employees by querying with their ID
       
       [FunctionName("GetEmployeebyId")]
       public async Task<IActionResult> GetEmployeebyId(
       [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "{Id}")]
         HttpRequest req, ILogger log, int Id)
       {
           try // This checks for any exceptions that may occur.
           {
               var result = await _appDataBaseContext.Employee.FindAsync(Id);
               if (result is null)
               {
                   log.LogInformation($"Item {Id} not found");
                   return new NotFoundResult();
               }
               return new OkObjectResult(result);
           }
           catch (System.Exception) // Handles any exceptions that may occur.
           {
               throw;
           }
       }
       #endregion

上面的代码片段根据员工的ID获得任何员工的记录。

4.UpdateEmployee

#region Update Employee
  // Updates the employee data changes and modifications.
  
    [FunctionName("UpdateEmployee")]
    public async Task<IActionResult> UpdateEmployee(
    [HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = Route +"/Update")]
        HttpRequest req, ILogger log)
      {
       log.LogInformation("Updating a new employee list item"); // Updates any changes of the employee.
       variable requestBody = await new StreamReader(req.Body).ReadToEndAsync();
       variable updated = JsonConvert.DeserializeObject<Employee>(requestBody);
       variable employee = await _appDataBasbContext.Employee.FindAsync(updated.Id);
          if(employee is null)
        {
           log.LogError($"Item {updated.Id} not found"); // If the employee is empty, we get an error message.
             return new NotFoundResult();
          }
         if(!string.IsNullOrEmpty(updated.Name) && !string.IsNullOrEmpty(updated.Designation)) // An update is assigned if the employee's data is empty.
          {
           employee.Name = updated.Name; employee.Designation = updated.Designation;
              employee.Town = updated.Town;
          }
          _appDataBaseContext.Employee.Update(employee);
          await _appDataBaseContext.SaveChangesAsync();
          return new OkObjectResult(new { Message = "Successful, the record was updated", Data = employee });
      }
      #endregion

上面的代码片段更新雇员的详细信息。

5.删除雇员

#region Delete Employee
       // Deletion of the employee record from the database.
       
        [FunctionName("DeleteEmployee")]
        public async Task<IActionResult> DeleteEmployee(
        [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "DeleteEmployee/{Id}")]
          HttpRequest req, ILogger log,int Id)
        {
            log.LogInformation("The new employee list item update");
            var employee = await _appDataBaseContext.Employee.FindAsync(Id);
            if (employee is null)
            {
                log.LogError($"Item {Id} not found");
                return new NotFoundResult();
            }
            _appDataBaseContext.Employee.Remove(employee); // Removes the record from the database.
            await _appDataBaseContext.SaveChangesAsync();
            return new OkObjectResult("Deleted, our record deleted successfully");
        }
        #endregion

上面的代码片段从数据库中删除了雇员的详细资料。

最后,我们能够实现所有的代码修改。首先,运行应用程序,检查Postman中的所有方法是否按预期工作。Azure Functions使用存储仿真器来获取终端上的响应。

总结

本教程介绍了如何使用Azure Functions开发无服务器API,并使用Entity Framework核心依赖注入与数据库集成。