Dapr 运用
前置條件
Docker
Win10
Dapr 部署
本文將采用本地部署的方式。
安裝 Dapr CLI
打開 Windows PowerShell 或 cmd ,運行以下命令以安裝?Dapr CLI,并添加安裝路徑到系統環境變量中。
powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"這里安裝可能會失敗。如果失敗可以手動安裝。
打開 Dapr?發布頁面下載?dapr_windows_amd64.zip
解壓文件 zip 文件
把解壓后的文件拷貝到?C:\dapr?中
安裝 MySql
Docker 啟動 Mysql
docker run --name mysqltest -e MYSQL_ROOT_PASSWORD=123456 -d mysql使用 Dapr CLI 安裝 Darp runtime
在 Windows PowerShell 或 cmd 中使用命令?dapr init?以安裝 Dapr。
同時可以在 Docker 中查看 Dapr 容器。
至此,一個本地 Dapr 服務搭建完成。
使用?Asp.Net Core?搭建 ProductService 服務
ProductService 提供兩個服務
獲取所有產品集合
添加產品
使用?ASP.Net Core?創建 ProductService ,具體參考源碼
Dapr 啟動 ProductService
dapr run --app-id productService --app-port 5000 dotnet run獲取所有產品集合,使用 curl 命令
curl -X GET http://localhost:5000/getlist或者
curl -X GET http://localhost:54680/v1.0/invoke/productService/method/getlist添加一個產品
curl -X POST https://localhost:5001/product -H "Content-Type: application/json" -d "{ \"id\": \"14a3611d-1561-455f-9c72-381eed2f6ee3\" }"重點,通過 Dapr 添加一個產品,先看添加產品的代碼
/// <summary>/// 創建產品/// </summary>/// <param name="productCreate">產品創建模型</param>/// <returns></returns>[Topic("product")][HttpPost("product")]public async Task<bool> CreateProduct(ProductCreate productCreate){_productContext.Products.Add(new Product{ProductID = productCreate.ID});return await _productContext.SaveChangesAsync() == 1;}使用 Dapr cli 發布事件
dapr invoke -a productService -m product -p "{\"id\":\"b1ccf14a-408a-428e-b0f0-06b97cbe4135\"}"輸出為:
true App invoked successfully使用 curl 命令直接請求 ProductService 地址
curl -X POST http://localhost:5000/product -H "Content-Type: application/json" -d "{ \"id\": \"14a3611d-1561-455f-9c72-381eed2f64e3\" }"輸出為:
true使用 curl 命令通過 Dapr runtime
curl -X POST http://localhost:54680/v1.0/invoke/productService/method/product -H "Content-Type: application/json" -d "{ \"id\": \"14a3611d-1561-455f-9c72-381eed2f54e3\" }"輸出為:
true
注意:
Dapr 使用 App 端口號應與服務端口號相同,例如:ASP.Net Core?服務端口號為5000,則在使用 Dapr 托管應用程序時的端口號也應使用 5000
至此, ProductService 創建完成。
使用 Golang 創建 gRPC Server
創建 Server
package mainimport ("context""fmt""log""net""github.com/golang/protobuf/ptypes/any""github.com/golang/protobuf/ptypes/empty"pb "github.com/dapr/go-sdk/daprclient""google.golang.org/grpc" )// server is our user app type server struct { }func main() {// create listinerlis, err := net.Listen("tcp", ":4000")if err != nil {log.Fatalf("failed to listen: %v", err)}// create grpc servers := grpc.NewServer()pb.RegisterDaprClientServer(s, &server{})fmt.Println("Client starting...")// and start...if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)} }// Sample method to invoke func (s *server) MyMethod() string {return "Hi there!" }// This method gets invoked when a remote service has called the app through Dapr // The payload carries a Method to identify the method, a set of metadata properties and an optional payload func (s *server) OnInvoke(ctx context.Context, in *pb.InvokeEnvelope) (*any.Any, error) {var response stringfmt.Println(fmt.Sprintf("Got invoked with: %s", string(in.Data.Value)))switch in.Method {case "MyMethod":response = s.MyMethod()}return &any.Any{Value: []byte(response),}, nil }// Dapr will call this method to get the list of topics the app wants to subscribe to. In this example, we are telling Dapr // To subscribe to a topic named TopicA func (s *server) GetTopicSubscriptions(ctx context.Context, in *empty.Empty) (*pb.GetTopicSubscriptionsEnvelope, error) {return &pb.GetTopicSubscriptionsEnvelope{Topics: []string{"TopicA"},}, nil }// Dapper will call this method to get the list of bindings the app will get invoked by. In this example, we are telling Dapr // To invoke our app with a binding named storage func (s *server) GetBindingsSubscriptions(ctx context.Context, in *empty.Empty) (*pb.GetBindingsSubscriptionsEnvelope, error) {return &pb.GetBindingsSubscriptionsEnvelope{Bindings: []string{"storage"},}, nil }// This method gets invoked every time a new event is fired from a registerd binding. The message carries the binding name, a payload and optional metadata func (s *server) OnBindingEvent(ctx context.Context, in *pb.BindingEventEnvelope) (*pb.BindingResponseEnvelope, error) {fmt.Println("Invoked from binding")return &pb.BindingResponseEnvelope{}, nil }// This method is fired whenever a message has been published to a topic that has been subscribed. Dapr sends published messages in a CloudEvents 0.3 envelope. func (s *server) OnTopicEvent(ctx context.Context, in *pb.CloudEventEnvelope) (*empty.Empty, error) {fmt.Println("Topic message arrived")return &empty.Empty{}, nil }使用 Dapr 命令啟動 StorageService
dapr run --app-id client --protocol grpc --app-port 4000 go run main.go注意:
Dapr 使用 App 端口號應與服務端口號相同,使用 --protocal grpc 指定通訊協議為 grpc 。此外,OnInvoke 中的 switch 方法用于調用者路由。
使用?ASP.NET Core?創建 StorageService
使用 NuGet 獲取程序管理包控制臺安裝以下包
Dapr.AspNetCore
Dapr.Client.Grpc
Grpc.AspNetCore
Grpc.Net.Client
Grpc.Tools
Startup.cs?文件中修改代碼如下:
/// <summary> /// This method gets called by the runtime. Use this method to add services to the container. /// </summary> /// <param name="services">Services.</param> public void ConfigureServices(IServiceCollection services) {services.AddControllers().AddDapr();services.AddDbContextPool<StorageContext>(options => { options.UseMySql(Configuration.GetConnectionString("MysqlConnection")); }); } /// <summary> /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. /// </summary> /// <param name="app">app.</param> /// <param name="env">env.</param> public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseRouting();app.UseCloudEvents();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapSubscribeHandler();endpoints.MapControllers();}); }添加?StorageController.cs?文件,內容如下
using System; using System.Linq; using System.Threading.Tasks; using Dapr.Client.Grpc; using Google.Protobuf; using Grpc.Net.Client; using Microsoft.AspNetCore.Mvc; using StorageService.Api.Entities;namespace StorageService.Api.Controllers {[ApiController]public class StorageController : ControllerBase{private readonly StorageContext _storageContext;public StorageController(StorageContext storageContext){_storageContext = storageContext;}/// <summary>/// 初始化倉庫./// </summary>/// <returns>是否成功.</returns>[HttpGet("InitialStorage")]public async Task<bool> InitialStorage(){string defaultPort = Environment.GetEnvironmentVariable("DAPR_GRPC_PORT") ?? "54681";// Set correct switch to make insecure gRPC service calls. This switch must be set before creating the GrpcChannel.AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);// Create Clientstring daprUri = $"http://127.0.0.1:{defaultPort}";GrpcChannel channel = GrpcChannel.ForAddress(daprUri);var client = new Dapr.Client.Grpc.Dapr.DaprClient(channel);Console.WriteLine(daprUri);InvokeServiceResponseEnvelope result = await client.InvokeServiceAsync(new InvokeServiceEnvelope{Method = "MyMethod",Id = "client",Data = new Google.Protobuf.WellKnownTypes.Any{Value = ByteString.CopyFromUtf8("Hello ProductService")}});Console.WriteLine("this is call result:" + result.Data.Value.ToStringUtf8());//var productResult = result.Data.Unpack<ProductList.V1.ProductList>();//Console.WriteLine("this is call result:" + productResult.Results.FirstOrDefault());return true;}/// <summary>/// 修改庫存/// </summary>/// <param name="storage"></param>/// <returns></returns>[HttpPut("Reduce")]public bool Reduce(Storage storage){Storage storageFromDb = _storageContext.Storage.FirstOrDefault(q => q.ProductID.Equals(storage.ProductID));if (storageFromDb == null){return false;}if (storageFromDb.Amount <= storage.Amount){return false;}storageFromDb.Amount -= storage.Amount;return true;}} }使用 Dapr cli 啟用 StorageService 服務
dapr run --app-id storageService --app-port 5003 dotnet run使用 curl 命令訪問 StorageService InitialStorage 方法
curl -X GET http://localhost:56349/v1.0/invoke/storageService/method/InitialStorage輸入
true其中打印信息為:
this is call result:Hi there!注意:
Dapr 使用 App 端口號應與服務端口號相同,例如:ASP.Net Core?服務端口號為5003,則在使用 Dapr 托管應用程序時的端口號也應使用 5003,在 Client.InvokeServiceAsync 中的 Id 指被調用方的 App-Id ,Method 指被調用方方法名稱。參考 Go Server 中 OnInvoke 方法的 Switch 。
源碼地址:https://github.com/SoMeDay-Zhang/DaprDemos
總結
- 上一篇: 如何评估一个人解决问题的能力
- 下一篇: 微软将中止支持 .NET Core 2.