1
- ================
1
+ ================
2
2
Xtensive.Orm.Web
3
3
================
4
4
5
5
Summary
6
6
-------
7
- The extension adds integration for DataObjects.Net Core and ASP.NET Core. It contains SessionManager class
8
- which is middleware and can be used as part of ASP.NET Core Pipeline. SessionManager opens session and transaction on going down the pipeline
9
- and disposes them on going up the pipeline.
7
+ The extension adds integration for DataObjects.Net and ASP.NET Core. It contains an action filter called SessionActionFilter
8
+ and a middleware called OpenSessionMiddleware. The action filter is useful for providing session per MVC action. The middleware,
9
+ though, has wider coverage and can provide session to actions, controllers, razor pages and to other middleware down the pipeline.
10
+ Both of them open session and transaction and at the end dispose them. As obsolete SessionManager, they complete transacton scope
11
+ by default unless an exeption appeared. (more info on https://dataobjects.net)
10
12
11
- SessionManager has the following features:
12
- 1. When Session.Current is accessed, and there is no current Session, it will provide a new instance of Session.
13
- In that case a new transaction will be created. It will be committed when the pipeline execution returns to SessionManager without any exception,
14
- otherwise it will be rolled back.
15
- 2. Setting SessionManager.Demand().HasErrors to true will lead to rollback of this transaction.
16
- 3. SessionManager.Current (and SessionManager.Demand()) returns the instance of SessionManager
17
- bound to the current pipeline execution, i.e. current SessionManager.
18
- Its Session property (if not null) is the same value as the one provided by Session.Current.
13
+ Prerequisites
14
+ -------------
15
+ DataObjects.Net 7 or later (https://dataobjects.net)
19
16
20
- Note that presence of SessionManager does not prevent you from creating Sessions manually.
21
- It operates relying on Session.Resolver event, which is raised only when there is no current Session.
17
+ Usage of action filter
18
+ ----------------------
22
19
23
- Finally, no automatic Session + transaction will be provided, if you don't use Session.Current/Session.Demand() methods
24
- in your code (directly or indirectly). So e.g. requests to static web pages won't lead to any DB interaction.
20
+ To start using action filter it should be added to action filters collection like so
25
21
26
- Prerequisites
27
- -------------
28
- DataObjects.Net Core 0.1 or later (http://dataobjects.net)
22
+ public class Startup
23
+ {
24
+ public Startup(IConfiguration configuration)
25
+ {
26
+
27
+ }
29
28
30
- Implementation
31
- --------------
32
- To start using SessionManager it should be added to ASP.NET Middleware pipeline in Startup class like in example below
29
+ public void ConfigureServices(IServiceCollection services)
30
+ {
31
+ var domain = BuildDomain();
32
+
33
+ // Domain should be available as service to have
34
+ // access to it from action filter.
35
+ services.AddSingleton<Domain>(domain);
36
+
37
+ // Adds SessionAccessor as scoped service (one instance per request).
38
+ // Session accessor will be able to access Session and TransactionScope
39
+ // instances which are in HttpContext
40
+ services.AddDataObjectsSessionAccessor();
41
+
42
+ // Adds the action filter
43
+ services.AddControllers(options => options.Filters.AddDataObjectsSessionActionFilter());
44
+ }
45
+
46
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
47
+ {
48
+ if (env.IsDevelopment()) {
49
+ app.UseDeveloperExceptionPage();
50
+ }
51
+ else {
52
+ app.UseExceptionHandler("/Home/Error");
53
+ }
54
+ app.UseStaticFiles()
55
+ .UseRouting()
56
+ .UseAuthorization()
57
+ .UseEndpoints(endpoints => {
58
+ endpoints.MapControllerRoute(
59
+ name: "default",
60
+ pattern: "{controller=Home}/{action=Index}/{id?}");
61
+ });
62
+ }
63
+ }
64
+
65
+
66
+ After action filter is added you can use it like in the example bellow
67
+
68
+ public class HomeController : Controller
69
+ {
70
+ // If action require Session and TransactionScope to be opened then
71
+ // just put parameter like in this method.
72
+ // Action filter will find it wrap action with session
73
+ public IActionResult Index([FromServices] SessionAccessor sessionAccessor)
74
+ {
75
+ var sessionInstance = sessionAccessor.Session;
76
+ var transactionScopeInstance = sessionAccessor.TransactionScope;
77
+
78
+ // some queries to database
79
+
80
+ return View();
81
+ }
82
+
83
+ // If action does not require opened Session
84
+ // then don't put SessionAccessor as parameter
85
+ // action filter will skip openings
86
+ public IActionResult Privacy()
87
+ {
88
+ return View();
89
+ }
90
+ }
91
+
92
+
93
+ Usage of Middleware
94
+ -------------------
95
+
96
+ The middleware is needed to be placed to pipeline before any other middleware that require access
97
+ to session. Pipeline may be configured like so
33
98
34
99
public class Startup
35
100
{
@@ -40,28 +105,132 @@ public class Startup
40
105
41
106
public void ConfigureServices(IServiceCollection services)
42
107
{
43
- // Configure services
108
+ var domain = BuildDomain();
109
+
110
+ // Domain should be available as service to have
111
+ // access to it from action filter.
112
+ services.AddSingleton<Domain>(domain);
113
+
114
+ // Adds SessionAccessor as scoped service (one instance per request).
115
+ // Session accessor will be able to access Session and TransactionScope
116
+ // instances which are in HttpContext
117
+ services.AddDataObjectsSessionAccessor();
118
+
119
+ // Adds the action filter
120
+ services.AddControllers();
44
121
}
45
122
46
123
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
47
124
{
48
- // Configure parts of the pipeline which are before SessionManager.
49
- // It will be unable to use SessionManager functionality in these parts
50
- // For instance,
125
+ if (env.IsDevelopment()) {
126
+ app.UseDeveloperExceptionPage();
127
+ }
128
+ else {
129
+ app.UseExceptionHandler("/Home/Error");
130
+ }
51
131
app.UseStaticFiles()
132
+ .UseRouting()// this middleware won't have opened session
133
+ .UseDataObjectsSessionOpener()// open Session and Transaction scope
134
+ .UseAuthorization()// this middleware and the rest down the pipe have Session access
135
+ .UseEndpoints(endpoints => {
136
+ endpoints.MapControllerRoute(
137
+ name: "default",
138
+ pattern: "{controller=Home}/{action=Index}/{id?}");
139
+ });
140
+ }
141
+ }
142
+
143
+ After that you can access opened Session and TransactionScope
52
144
53
- // Add session manager to the pipeline
54
- app.UseSessionManager();
55
-
56
- // Configure parts of the pipeline which are after SessionManager.
57
- // These parts will work with SessionManager.
58
-
59
- // For instance, MVC controllers will be able to query data using DataObjects.Net
60
- app.UseMvc(routes =>
145
+ public class HomeController : Controller
146
+ {
147
+ // access from controller's constructor
148
+ public HomeController(SessionAccessor sessionAccessor)
149
+ {
150
+ // some work
151
+ }
152
+
153
+ // access from action
154
+ public IActionResult Index([FromServices] SessionAccessor sessionAccessor)
155
+ {
156
+ var sessionInstance = sessionAccessor.Session;
157
+ var transactionScopeInstance = sessionAccessor.TransactionScope;
158
+
159
+ // some queries to database
160
+
161
+ return View();
162
+ }
163
+
164
+ // NOTE that here session is opened too,
165
+ // even there is no SessionAccessor as parameter
166
+ // this is the difference in work of middleware and action filter
167
+ public IActionResult Privacy()
168
+ {
169
+ return View();
170
+ }
171
+ }
172
+
173
+
174
+ The middleware is also usable in Razor Pages projects. In this case
175
+ your Startup class may look like this:
176
+
177
+ public class Startup
178
+ {
179
+ public Startup(IConfiguration configuration)
180
+ {
181
+ Configuration = configuration;
182
+ }
183
+
184
+ public IConfiguration Configuration { get; }
185
+
186
+ // This method gets called by the runtime. Use this method to add services to the container.
187
+ public void ConfigureServices(IServiceCollection services)
188
+ {
189
+ var domain = Domain.Build();
190
+ services.AddSingleton(domain);
191
+ services.AddDataObjectsSessionAccessor();
192
+ services.AddRazorPages();
193
+ }
194
+
195
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
196
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
197
+ {
198
+ if (env.IsDevelopment()) {
199
+ app.UseDeveloperExceptionPage();
200
+ }
201
+ else {
202
+ app.UseExceptionHandler("/Error");
203
+ }
204
+
205
+ app.UseStaticFiles();
206
+
207
+ app.UseRouting();
208
+
209
+ app.UseAuthorization();
210
+
211
+ app.UseDataObjectsSessionOpener();
212
+
213
+ app.UseEndpoints(endpoints =>
61
214
{
62
- routes.MapRoute(
63
- name: "default",
64
- template: "{controller=Home}/{action=Index}/{id?}");
215
+ endpoints.MapRazorPages();
65
216
});
66
217
}
218
+ }
219
+
220
+ And then in actual pages you can use SessionAccessor like below
221
+
222
+ public class IndexModel : PageModel
223
+ {
224
+
225
+ public IndexModel(SessionAccessor accessor)
226
+ {
227
+ _logger = logger;
228
+ }
229
+
230
+ public void OnGet([FromServices] SessionAccessor sessionAccessor)
231
+ {
232
+ var sessionInstance = sessionAccessor.Session;
233
+
234
+ // query some data from database
235
+ }
67
236
}
0 commit comments