Skip to content

Commit c6a8379

Browse files
committed
Merged
2 parents d113838 + 3768a98 commit c6a8379

File tree

18 files changed

+606
-46
lines changed

18 files changed

+606
-46
lines changed

.github/workflows/itests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ jobs:
4343
GOARCH: amd64
4444
GOPROXY: https://proxy.golang.org
4545
DAPR_CLI_VER: 1.13.0
46-
DAPR_RUNTIME_VER: 1.13.0
47-
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/release-1.13/install/install.sh
46+
DAPR_RUNTIME_VER: 1.13.2
47+
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/release-1.12/install/install.sh
4848
DAPR_CLI_REF: ''
4949
steps:
5050
- name: Set up Dapr CLI

all.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ EndProject
3232
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1BD1276E-D28A-45EA-89B1-6AD48471500D}"
3333
ProjectSection(SolutionItems) = preProject
3434
.editorconfig = .editorconfig
35+
README.md = README.md
3536
EndProjectSection
3637
EndProject
3738
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapr.Actors.AspNetCore.Test", "test\Dapr.Actors.AspNetCore.Test\Dapr.Actors.AspNetCore.Test.csproj", "{9C1D6ABA-5EDE-4FA0-A8A9-0AB98CB74737}"
Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

3-
<PropertyGroup>
4-
<TargetFramework>net6</TargetFramework>
5-
</PropertyGroup>
6-
7-
<ItemGroup>
8-
<ProjectReference Include="..\..\..\src\Dapr.Actors.AspNetCore\Dapr.Actors.AspNetCore.csproj" />
9-
<ProjectReference Include="..\..\..\src\Dapr.Actors\Dapr.Actors.csproj" />
10-
<ProjectReference Include="..\IDemoActor\IDemoActor.csproj" />
11-
</ItemGroup>
3+
<PropertyGroup>
4+
<TargetFramework>net6</TargetFramework>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<IsPublishable>true</IsPublishable>
9+
<EnableSdkContainerSupport>true</EnableSdkContainerSupport>
10+
<ContainerRepository>demo-actor</ContainerRepository>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<ContainerEnvironmentVariable Include="ASPNETCORE_URLS" Value="http://+:8080" />
15+
<ContainerPort Include="8080" Type="tcp" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<ProjectReference Include="..\..\..\src\Dapr.Actors.AspNetCore\Dapr.Actors.AspNetCore.csproj" />
20+
<ProjectReference Include="..\..\..\src\Dapr.Actors\Dapr.Actors.csproj" />
21+
<ProjectReference Include="..\IDemoActor\IDemoActor.csproj" />
22+
</ItemGroup>
1223

1324
</Project>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
apiVersion: dapr.io/v1alpha1
2+
kind: Component
3+
metadata:
4+
name: statestore
5+
spec:
6+
type: state.in-memory
7+
version: v1
8+
metadata:
9+
- name: actorStateStore
10+
value: "true"
11+
---
12+
kind: Service
13+
apiVersion: v1
14+
metadata:
15+
name: demoactor
16+
labels:
17+
app: demoactor
18+
spec:
19+
selector:
20+
app: demoactor
21+
ports:
22+
- name: app-port
23+
protocol: TCP
24+
port: 5010
25+
targetPort: app-port
26+
- name: dapr-http
27+
protocol: TCP
28+
port: 3500
29+
targetPort: 3500
30+
type: LoadBalancer
31+
---
32+
apiVersion: apps/v1
33+
kind: Deployment
34+
metadata:
35+
name: demoactor
36+
labels:
37+
app: demoactor
38+
spec:
39+
replicas: 1
40+
selector:
41+
matchLabels:
42+
app: demoactor
43+
template:
44+
metadata:
45+
labels:
46+
app: demoactor
47+
annotations:
48+
dapr.io/enabled: "true"
49+
dapr.io/app-id: "demoactor"
50+
dapr.io/app-port: "5010"
51+
dapr.io/enable-api-logging: "true"
52+
dapr.io/sidecar-listen-addresses: "0.0.0.0"
53+
spec:
54+
containers:
55+
- name: demoactor
56+
# image: <your-docker-registry>/demo-actor:latest
57+
image: demo-actor:latest
58+
# if you are using docker desktop, you can use imagePullPolicy: Never to use local image
59+
imagePullPolicy: Never
60+
env:
61+
- name: APP_PORT
62+
value: "5010"
63+
- name: ASPNETCORE_URLS
64+
value: "http://+:5010"
65+
ports:
66+
- name: app-port
67+
containerPort: 5010

examples/Actor/README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,80 @@ On Windows:
7979
``` powershell
8080
Invoke-WebRequest -Method POST -Uri http://127.0.0.1:3500/v1.0/actors/DemoActor/abc/method/GetData
8181
```
82+
83+
### Build and push Docker image
84+
You can build the docker image of `DemoActor` service by running the following commands in the `DemoActor` project directory:
85+
86+
``` Bash
87+
dotnet publish --os linux --arch x64 /t:PublishContainer -p ContainerImageTags='"latest"' --self-contained
88+
```
89+
90+
The build produce and image with tag `demo-actor:latest` and load it in the local registry.
91+
Now the image can be pushed to your remote Docker registry by running the following commands:
92+
93+
``` Bash
94+
# Replace <your-docker-registry> with your Docker registry
95+
docker tag demo-actor:latest <your-docker-registry>/demo-actor:latest
96+
97+
# Push the image to your Docker registry
98+
docker push <your-docker-registry>/demo-actor:latest
99+
```
100+
101+
### Deploy the Actor service to Kubernetes
102+
#### Prerequisites
103+
- A Kubernetes cluster with `kubectl` configured to access it.
104+
- Dapr v1.13+ installed on the Kubernetes cluster. Follow the instructions [here](https://docs.dapr.io/getting-started/install-dapr-kubernetes/).
105+
- A Docker registry where you pushed the `DemoActor` image.
106+
107+
#### Deploy the Actor service
108+
For quick deployment you can install dapr in dev mode using the following command:
109+
110+
``` Bash
111+
dapr init -k --dev
112+
```
113+
114+
To deploy the `DemoActor` service to Kubernetes, you can use the provided Kubernetes manifest file `demo-actor.yaml` in the `DemoActor` project directory.
115+
Before applying the manifest file, replace the image name in the manifest file with the image name you pushed to your Docker registry.
116+
117+
Part to update in `demo-actor.yaml`:
118+
``` YAML
119+
image: <your-docker-registry>/demoactor:latest
120+
```
121+
122+
To install the application in `default` namespace, run the following command:
123+
124+
``` Bash
125+
kubectl apply -f demo-actor.yaml
126+
```
127+
128+
This will deploy the `DemoActor` service to Kubernetes. You can check the status of the deployment by running:
129+
130+
``` Bash
131+
kubectl get pods -n default --watch
132+
```
133+
134+
The manifest create 2 services:
135+
136+
- `demoactor` service: The service that hosts the `DemoActor` actor.
137+
- `demoactor-dapr` service: The service that hosts the Dapr sidecar for the `DemoActor` actor.
138+
139+
### Make client calls to the deployed Actor service
140+
To make client calls to the deployed `DemoActor` service, you can use the `ActorClient` project.
141+
Before running the client, update the `DAPR_HTTP_PORT` environment variable in the `ActorClient` project directory to the port on which Dapr is running in the Kubernetes cluster.
142+
143+
On Linux, MacOS:
144+
``` Bash
145+
export DAPR_HTTP_PORT=3500
146+
```
147+
148+
Than port-forward the `DemoActor` service to your local machine:
149+
150+
``` Bash
151+
kubectl port-forward svc/demoactor 3500:3500
152+
```
153+
154+
Now you can run the client project from the `ActorClient` directory:
155+
156+
``` Bash
157+
dotnet run
158+
```

src/Dapr.Actors/ActorReference.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ------------------------------------------------------------------------
1+
// ------------------------------------------------------------------------
22
// Copyright 2021 The Dapr Authors
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@ namespace Dapr.Actors
1616
using System;
1717
using System.Runtime.Serialization;
1818
using Dapr.Actors.Client;
19+
using Dapr.Actors.Runtime;
1920

2021
/// <summary>
2122
/// Encapsulation of a reference to an actor for serialization.
@@ -69,23 +70,28 @@ public object Bind(Type actorInterfaceType)
6970

7071
private static ActorReference GetActorReference(object actor)
7172
{
72-
if (actor == null)
73-
{
74-
throw new ArgumentNullException("actor");
75-
}
73+
ArgumentNullException.ThrowIfNull(actor, nameof(actor));
7674

77-
// try as IActorProxy for backward compatibility as customers's mock framework may rely on it before V2 remoting stack.
78-
if (actor is IActorProxy actorProxy)
75+
var actorReference = actor switch
7976
{
80-
return new ActorReference()
77+
// try as IActorProxy for backward compatibility as customers's mock framework may rely on it before V2 remoting stack.
78+
IActorProxy actorProxy => new ActorReference()
8179
{
8280
ActorId = actorProxy.ActorId,
8381
ActorType = actorProxy.ActorType,
84-
};
85-
}
82+
},
83+
// Handle case when we want to get ActorReference inside the Actor implementation,
84+
// we gather actor id and actor type from Actor base class.
85+
Actor actorBase => new ActorReference()
86+
{
87+
ActorId = actorBase.Id,
88+
ActorType = actorBase.Host.ActorTypeInfo.ActorTypeName,
89+
},
90+
// Handle case when we can't cast to IActorProxy or Actor.
91+
_ => throw new ArgumentOutOfRangeException("actor", "Invalid actor object type."),
92+
};
8693

87-
// TODO check for ActorBase
88-
throw new ArgumentOutOfRangeException("actor");
94+
return actorReference;
8995
}
9096
}
9197
}

src/Dapr.AspNetCore/DaprServiceCollectionExtensions.cs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,32 @@ public static class DaprServiceCollectionExtensions
3131
/// <param name="configure"></param>
3232
public static void AddDaprClient(this IServiceCollection services, Action<DaprClientBuilder> configure = null)
3333
{
34-
if (services is null)
35-
{
36-
throw new ArgumentNullException(nameof(services));
37-
}
34+
ArgumentNullException.ThrowIfNull(services, nameof(services));
3835

3936
services.TryAddSingleton(_ =>
4037
{
4138
var builder = new DaprClientBuilder();
42-
if (configure != null)
43-
{
44-
configure.Invoke(builder);
45-
}
39+
configure?.Invoke(builder);
40+
41+
return builder.Build();
42+
});
43+
}
44+
45+
/// <summary>
46+
/// Adds Dapr client services to the provided <see cref="IServiceCollection"/>. This does not include integration
47+
/// with ASP.NET Core MVC. Use the <c>AddDapr()</c> extension method on <c>IMvcBuilder</c> to register MVC integration.
48+
/// </summary>
49+
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
50+
/// <param name="configure"></param>
51+
public static void AddDaprClient(this IServiceCollection services,
52+
Action<IServiceProvider, DaprClientBuilder> configure)
53+
{
54+
ArgumentNullException.ThrowIfNull(services, nameof(services));
55+
56+
services.TryAddSingleton(serviceProvider =>
57+
{
58+
var builder = new DaprClientBuilder();
59+
configure?.Invoke(serviceProvider, builder);
4660

4761
return builder.Build();
4862
});

src/Dapr.Client/DaprClient.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,20 @@ public HttpRequestMessage CreateInvokeMethodRequest(string appId, string methodN
306306
return CreateInvokeMethodRequest(HttpMethod.Post, appId, methodName);
307307
}
308308

309+
/// <summary>
310+
/// Creates an <see cref="HttpRequestMessage" /> that can be used to perform service invocation for the
311+
/// application identified by <paramref name="appId" /> and invokes the method specified by <paramref name="methodName" />
312+
/// with the <c>POST</c> HTTP method.
313+
/// </summary>
314+
/// <param name="appId">The Dapr application id to invoke the method on.</param>
315+
/// <param name="methodName">The name of the method to invoke.</param>
316+
/// <param name="queryStringParameters">A collection of key/value pairs to populate the query string from.</param>
317+
/// <returns>An <see cref="HttpRequestMessage" /> for use with <c>SendInvokeMethodRequestAsync</c>.</returns>
318+
public HttpRequestMessage CreateInvokeMethodRequest(string appId, string methodName, IReadOnlyCollection<KeyValuePair<string,string>> queryStringParameters)
319+
{
320+
return CreateInvokeMethodRequest(HttpMethod.Post, appId, methodName, queryStringParameters);
321+
}
322+
309323
/// <summary>
310324
/// Creates an <see cref="HttpRequestMessage" /> that can be used to perform service invocation for the
311325
/// application identified by <paramref name="appId" /> and invokes the method specified by <paramref name="methodName" />
@@ -317,6 +331,19 @@ public HttpRequestMessage CreateInvokeMethodRequest(string appId, string methodN
317331
/// <returns>An <see cref="HttpRequestMessage" /> for use with <c>SendInvokeMethodRequestAsync</c>.</returns>
318332
public abstract HttpRequestMessage CreateInvokeMethodRequest(HttpMethod httpMethod, string appId, string methodName);
319333

334+
/// <summary>
335+
/// Creates an <see cref="HttpRequestMessage" /> that can be used to perform service invocation for the
336+
/// application identified by <paramref name="appId" /> and invokes the method specified by <paramref name="methodName" />
337+
/// with the HTTP method specified by <paramref name="httpMethod" />.
338+
/// </summary>
339+
/// <param name="httpMethod">The <see cref="HttpMethod" /> to use for the invocation request.</param>
340+
/// <param name="appId">The Dapr application id to invoke the method on.</param>
341+
/// <param name="methodName">The name of the method to invoke.</param>
342+
/// <param name="queryStringParameters">A collection of key/value pairs to populate the query string from.</param>
343+
/// <returns>An <see cref="HttpRequestMessage" /> for use with <c>SendInvokeMethodRequestAsync</c>.</returns>
344+
public abstract HttpRequestMessage CreateInvokeMethodRequest(HttpMethod httpMethod, string appId,
345+
string methodName, IReadOnlyCollection<KeyValuePair<string, string>> queryStringParameters);
346+
320347
/// <summary>
321348
/// Creates an <see cref="HttpRequestMessage" /> that can be used to perform service invocation for the
322349
/// application identified by <paramref name="appId" /> and invokes the method specified by <paramref name="methodName" />
@@ -329,9 +356,9 @@ public HttpRequestMessage CreateInvokeMethodRequest(string appId, string methodN
329356
/// <returns>An <see cref="HttpRequestMessage" /> for use with <c>SendInvokeMethodRequestAsync</c>.</returns>
330357
public HttpRequestMessage CreateInvokeMethodRequest<TRequest>(string appId, string methodName, TRequest data)
331358
{
332-
return CreateInvokeMethodRequest<TRequest>(HttpMethod.Post, appId, methodName, data);
359+
return CreateInvokeMethodRequest(HttpMethod.Post, appId, methodName, new List<KeyValuePair<string, string>>(), data);
333360
}
334-
361+
335362
/// <summary>
336363
/// Creates an <see cref="HttpRequestMessage" /> that can be used to perform service invocation for the
337364
/// application identified by <paramref name="appId" /> and invokes the method specified by <paramref name="methodName" />
@@ -343,9 +370,10 @@ public HttpRequestMessage CreateInvokeMethodRequest<TRequest>(string appId, stri
343370
/// <param name="appId">The Dapr application id to invoke the method on.</param>
344371
/// <param name="methodName">The name of the method to invoke.</param>
345372
/// <param name="data">The data that will be JSON serialized and provided as the request body.</param>
373+
/// <param name="queryStringParameters">A collection of key/value pairs to populate the query string from.</param>
346374
/// <returns>An <see cref="HttpRequestMessage" /> for use with <c>SendInvokeMethodRequestAsync</c>.</returns>
347-
public abstract HttpRequestMessage CreateInvokeMethodRequest<TRequest>(HttpMethod httpMethod, string appId, string methodName, TRequest data);
348-
375+
public abstract HttpRequestMessage CreateInvokeMethodRequest<TRequest>(HttpMethod httpMethod, string appId, string methodName, IReadOnlyCollection<KeyValuePair<string,string>> queryStringParameters, TRequest data);
376+
349377
/// <summary>
350378
/// Perform health-check of Dapr sidecar. Return 'true' if sidecar is healthy. Otherwise 'false'.
351379
/// CheckHealthAsync handle <see cref="HttpRequestException"/> and will return 'false' if error will occur on transport level
@@ -526,7 +554,7 @@ public Task InvokeMethodAsync<TRequest>(
526554
TRequest data,
527555
CancellationToken cancellationToken = default)
528556
{
529-
var request = CreateInvokeMethodRequest<TRequest>(httpMethod, appId, methodName, data);
557+
var request = CreateInvokeMethodRequest<TRequest>(httpMethod, appId, methodName, new List<KeyValuePair<string, string>>(), data);
530558
return InvokeMethodAsync(request, cancellationToken);
531559
}
532560

@@ -620,7 +648,7 @@ public Task<TResponse> InvokeMethodAsync<TRequest, TResponse>(
620648
TRequest data,
621649
CancellationToken cancellationToken = default)
622650
{
623-
var request = CreateInvokeMethodRequest<TRequest>(httpMethod, appId, methodName, data);
651+
var request = CreateInvokeMethodRequest<TRequest>(httpMethod, appId, methodName, new List<KeyValuePair<string, string>>(), data);
624652
return InvokeMethodAsync<TResponse>(request, cancellationToken);
625653
}
626654

0 commit comments

Comments
 (0)