Skip to content

Commit 05446ff

Browse files
committed
Update ReadMe file of Web extension
1 parent b1e55c1 commit 05446ff

File tree

1 file changed

+206
-37
lines changed

1 file changed

+206
-37
lines changed
Lines changed: 206 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,100 @@
1-
================
1+
================
22
Xtensive.Orm.Web
33
================
44

55
Summary
66
-------
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)
1012

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)
1916

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+
----------------------
2219

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
2521

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+
}
2928

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
3398

3499
public class Startup
35100
{
@@ -40,28 +105,132 @@ public class Startup
40105

41106
public void ConfigureServices(IServiceCollection services)
42107
{
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();
44121
}
45122

46123
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
47124
{
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+
}
51131
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
52144

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 =>
61214
{
62-
routes.MapRoute(
63-
name: "default",
64-
template: "{controller=Home}/{action=Index}/{id?}");
215+
endpoints.MapRazorPages();
65216
});
66217
}
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+
}
67236
}

0 commit comments

Comments
 (0)