-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathUserSvc.cs
133 lines (114 loc) · 4.95 KB
/
UserSvc.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System;
using System.Collections.Generic;
using System.Fabric;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ServiceFabric.Data;
using Microsoft.ServiceFabric.Data.Collections;
using Microsoft.ServiceFabric.Services.Communication.AspNetCore;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;
using Basic.Common;
using ServiceFabric.Extensions.Data.Indexing.Persistent;
using ServiceFabric.Extensions.Services.Queryable.LINQ;
namespace Basic.UserSvc
{
/// <summary>
/// The FabricRuntime creates an instance of this class for each service type instance.
/// </summary>
internal sealed class UserSvc : StatefulService
{
public UserSvc(StatefulServiceContext context)
: base(context)
{ }
/// <summary>
/// Optional override to create listeners (like tcp, http) for this service instance.
/// </summary>
/// <returns>The collection of listeners.</returns>
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new ServiceReplicaListener[]
{
new ServiceReplicaListener(serviceContext =>
new KestrelCommunicationListener(serviceContext, (url, listener) =>
{
return new WebHostBuilder()
.UseKestrel()
.ConfigureServices(
services => services
.AddSingleton<StatefulServiceContext>(serviceContext)
.AddSingleton<IReliableStateManager>(this.StateManager))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseApplicationInsights()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
.UseUrls(url)
.Build();
}))
};
}
protected override async Task RunAsync(CancellationToken cancellationToken)
{
// Make a traditional IReliableDictionary <UserName, UserProfile>
var users = await StateManager.GetOrAddAsync<IReliableDictionary<UserName, UserProfile>>("users");
// Make an IReliableIndexedDictionary <UserName, UserProfile>, with two indices:
// Index<UserProfile.Email, UserName[]> and Index<UserProfile.Age, UserName[]>
var indexed_users = await StateManager.GetOrAddIndexedAsync<UserName, UserProfile>("indexed_users",
FilterableIndex<UserName, UserProfile, string>.CreateQueryableInstance("Email"),
FilterableIndex<UserName, UserProfile, int>.CreateQueryableInstance("Age"));
// The above dictionaries have the same content (below), but because the second has indices,
// Linq queries and external queries should use that and be faster.
for (int i = 0; i < 100; i++)
{
using (var tx = StateManager.CreateTransaction())
{
var user = new UserProfile
{
Name = new UserName
{
First = $"First{i}",
Last = $"Last{i}",
},
Email = $"user-{i}@example.com",
Age = 20 + i / 3,
Address = new Address
{
AddressLine1 = $"1{i} Main St.",
City = "Seattle",
State = "WA",
Zipcode = 98117,
},
};
await users.SetAsync(tx, user.Name, user, TimeSpan.FromSeconds(4), cancellationToken);
await indexed_users.SetAsync(tx, user.Name, user, TimeSpan.FromSeconds(4), cancellationToken);
await tx.CommitAsync();
}
}
/* Example of LINQ querying on IReliableIndexedDictionary
Sometimes you will want your application code to carry out queries against your RC as well, and LINQ is a great way to do so
Also, when you write your query, make sure to put all your WHERE logic into a single WHERE statement
since each statement carries its own context the indexing middleware cannot efficiently operate on disjoint statements,
e.g. use qdict.Where(x => x.Email == "user-0@example.com" && x.Age <= 20) instead of
qdict.Where(x => x.Email == "user-0@example.com").Where(x => x.Age <= 20)
*/
// Create LINQ-Queryable state of IndexedDictionary
var qdict = new QueryableReliableIndexedDictionary<UserName, UserProfile, UserProfile>(indexed_users, StateManager);
// Create the same query two different ways
var query = from UserProfile profile in qdict
where profile.Age >= 20 && profile.Email == "user-0@example.com" && profile.Age <= 20
select profile;
var query2 = qdict.Where(x => x.Email == "user-0@example.com" && x.Age <= 20);
// Execute the queries, add breakpoints here to see results
foreach (UserProfile profile in query)
{
}
foreach (UserProfile profile in query2)
{
}
}
}
}