diff --git a/src/EmailMaker.Website/EmailMaker.Website.csproj b/src/EmailMaker.Website/EmailMaker.Website.csproj
index 31123bd..bad2551 100644
--- a/src/EmailMaker.Website/EmailMaker.Website.csproj
+++ b/src/EmailMaker.Website/EmailMaker.Website.csproj
@@ -233,8 +233,8 @@
Global.asax
-
-
+
+
diff --git a/src/EmailMaker.Website/TransactionScopeUnitOfWorkHttpModule.cs b/src/EmailMaker.Website/HttpModules/TransactionScopeUnitOfWorkHttpModule.cs
similarity index 92%
rename from src/EmailMaker.Website/TransactionScopeUnitOfWorkHttpModule.cs
rename to src/EmailMaker.Website/HttpModules/TransactionScopeUnitOfWorkHttpModule.cs
index b8c111d..e214cd6 100644
--- a/src/EmailMaker.Website/TransactionScopeUnitOfWorkHttpModule.cs
+++ b/src/EmailMaker.Website/HttpModules/TransactionScopeUnitOfWorkHttpModule.cs
@@ -6,13 +6,15 @@
using CoreUtils.Storages;
using Rebus.TransactionScopes;
-namespace EmailMaker.Website
+namespace EmailMaker.Website.HttpModules
{
// register TransactionScopeUnitOfWorkHttpModule in the web.config (system.webServer -> modules)
// transaction scope is needed to send messages to EmailMaker service only when the DB transaction successfully commits
// https://stackoverflow.com/a/8169117/379279
public class TransactionScopeUnitOfWorkHttpModule : IHttpModule
{
+ private const IsolationLevel DefaultIsolationLevel = IsolationLevel.ReadCommitted;
+
public void Init(HttpApplication application)
{
application.BeginRequest += Application_BeginRequest;
@@ -66,7 +68,7 @@ private TransactionScope GetTransactionScopePerWebRequest()
{
var newTransactionScope = new TransactionScope(
TransactionScopeOption.Required,
- new TransactionOptions {IsolationLevel = IsolationLevel.ReadCommitted},
+ new TransactionOptions {IsolationLevel = DefaultIsolationLevel},
TransactionScopeAsyncFlowOption.Enabled
);
transactionScopeStoragePerWebRequest.Set(newTransactionScope);
diff --git a/src/EmailMaker.Website/UnitOfWorkHttpModule.cs b/src/EmailMaker.Website/HttpModules/UnitOfWorkHttpModule.cs
similarity index 86%
rename from src/EmailMaker.Website/UnitOfWorkHttpModule.cs
rename to src/EmailMaker.Website/HttpModules/UnitOfWorkHttpModule.cs
index 279d7c2..1eba1bd 100644
--- a/src/EmailMaker.Website/UnitOfWorkHttpModule.cs
+++ b/src/EmailMaker.Website/HttpModules/UnitOfWorkHttpModule.cs
@@ -1,14 +1,17 @@
using System;
+using System.Data;
using System.Web;
using CoreDdd.Domain.Events;
using CoreDdd.UnitOfWorks;
using CoreIoC;
-namespace EmailMaker.Website
+namespace EmailMaker.Website.HttpModules
{
// register UnitOfWorkHttpModule in the web.config (system.webServer -> modules)
public class UnitOfWorkHttpModule : IHttpModule
{
+ private const IsolationLevel DefaultIsolationLevel = IsolationLevel.ReadCommitted;
+
public void Init(HttpApplication application)
{
DomainEvents.EnableDelayedDomainEventHandling(); // messages sent from domain event handlers would not be sent if the main DB transaction rolls back
@@ -21,7 +24,7 @@ public void Init(HttpApplication application)
private void Application_BeginRequest(Object source, EventArgs e)
{
var unitOfWork = GetUnitOfWorkPerWebRequest();
- unitOfWork.BeginTransaction();
+ unitOfWork.BeginTransaction(DefaultIsolationLevel);
}
private void Application_EndRequest(Object source, EventArgs e)
@@ -40,7 +43,7 @@ private void _DomainEventHandlingSurroundingTransaction(Action domainEventHandli
try
{
- unitOfWork.BeginTransaction();
+ unitOfWork.BeginTransaction(DefaultIsolationLevel);
domainEventHandlingAction();
diff --git a/src/EmailMaker.Website/Web.config b/src/EmailMaker.Website/Web.config
index fcef6fa..ae0c122 100644
--- a/src/EmailMaker.Website/Web.config
+++ b/src/EmailMaker.Website/Web.config
@@ -50,8 +50,8 @@
-
-
+
+
diff --git a/src/EmailMaker.WebsiteCore/Middleware/TransactionScopeUnitOfWorkMiddleware.cs b/src/EmailMaker.WebsiteCore/Middleware/TransactionScopeUnitOfWorkMiddleware.cs
index 2e42658..45b1201 100644
--- a/src/EmailMaker.WebsiteCore/Middleware/TransactionScopeUnitOfWorkMiddleware.cs
+++ b/src/EmailMaker.WebsiteCore/Middleware/TransactionScopeUnitOfWorkMiddleware.cs
@@ -12,13 +12,28 @@ namespace EmailMaker.WebsiteCore.Middleware
// https://stackoverflow.com/a/8169117/379279
public class TransactionScopeUnitOfWorkMiddleware : IMiddleware
{
+ private readonly IsolationLevel _isolationLevel;
+
+ public TransactionScopeUnitOfWorkMiddleware(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
+ {
+ _isolationLevel = isolationLevel;
+ }
+
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
- _BeginRequest();
+ try
+ {
+ _BeginRequest();
- await next.Invoke(context);
+ await next.Invoke(context);
- _EndRequest();
+ _EndRequest();
+ }
+ catch
+ {
+ _HandleErrorInRequest();
+ throw;
+ }
}
private void _BeginRequest()
@@ -32,8 +47,6 @@ private void _BeginRequest()
private void _EndRequest()
{
- //if (HttpContext.Current.Server.GetLastError() != null) return; // todo: check out asp.net core error handling
-
var unitOfWork = GetUnitOfWorkPerWebRequest();
unitOfWork.Commit();
@@ -42,14 +55,14 @@ private void _EndRequest()
transactionScope.Dispose();
}
- // private void Application_Error(Object source, EventArgs e) // todo: check out asp.net core error handling
- // {
- // var unitOfWork = GetUnitOfWorkPerWebRequest();
- // unitOfWork.Rollback();
- //
- // var transactionScope = GetTransactionScopePerWebRequest();
- // transactionScope.Dispose();
- // }
+ private void _HandleErrorInRequest()
+ {
+ var unitOfWork = GetUnitOfWorkPerWebRequest();
+ unitOfWork.Rollback();
+
+ var transactionScope = GetTransactionScopePerWebRequest();
+ transactionScope.Dispose();
+ }
private IUnitOfWork GetUnitOfWorkPerWebRequest()
{
@@ -63,7 +76,7 @@ private TransactionScope GetTransactionScopePerWebRequest()
{
var newTransactionScope = new TransactionScope(
TransactionScopeOption.Required,
- new TransactionOptions {IsolationLevel = IsolationLevel.ReadCommitted},
+ new TransactionOptions {IsolationLevel = _isolationLevel},
TransactionScopeAsyncFlowOption.Enabled
);
transactionScopeStorage.Set(newTransactionScope);
diff --git a/src/EmailMaker.WebsiteCore/Middleware/UnitOfWorkMiddleware.cs b/src/EmailMaker.WebsiteCore/Middleware/UnitOfWorkMiddleware.cs
index f422499..3e6243a 100644
--- a/src/EmailMaker.WebsiteCore/Middleware/UnitOfWorkMiddleware.cs
+++ b/src/EmailMaker.WebsiteCore/Middleware/UnitOfWorkMiddleware.cs
@@ -1,4 +1,5 @@
using System;
+using System.Data;
using System.Threading.Tasks;
using CoreDdd.Domain.Events;
using CoreDdd.UnitOfWorks;
@@ -9,30 +10,39 @@ namespace EmailMaker.WebsiteCore.Middleware
{
public class UnitOfWorkMiddleware : IMiddleware
{
- public UnitOfWorkMiddleware()
+ private readonly IsolationLevel _isolationLevel;
+
+ public UnitOfWorkMiddleware(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)
{
+ _isolationLevel = isolationLevel;
DomainEvents.EnableDelayedDomainEventHandling(); // make sure messages sent from domain event handlers will not be sent if the main DB transaction rolls back
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
- _BeginRequest();
+ try
+ {
+ _BeginRequest();
- await next.Invoke(context);
+ await next.Invoke(context);
- _EndRequest();
+ _EndRequest();
+ }
+ catch
+ {
+ _HandleErrorInRequest();
+ throw;
+ }
}
private void _BeginRequest()
{
var unitOfWork = GetUnitOfWorkPerWebRequest();
- unitOfWork.BeginTransaction();
+ unitOfWork.BeginTransaction(_isolationLevel);
}
private void _EndRequest()
{
- //if (HttpContext.Current.Server.GetLastError() != null) return; // todo: check out asp.net core error handling
-
var unitOfWork = GetUnitOfWorkPerWebRequest();
unitOfWork.Commit();
@@ -45,7 +55,7 @@ private void _DomainEventHandlingSurroundingTransaction(Action domainEventHandli
try
{
- unitOfWork.BeginTransaction();
+ unitOfWork.BeginTransaction(_isolationLevel);
domainEventHandlingAction();
@@ -57,12 +67,12 @@ private void _DomainEventHandlingSurroundingTransaction(Action domainEventHandli
throw;
}
}
- //
- // private void Application_Error(Object source, EventArgs e) // todo: check out asp.net core error handling
- // {
- // var unitOfWork = GetUnitOfWorkPerWebRequest();
- // unitOfWork.Rollback();
- // }
+
+ private void _HandleErrorInRequest()
+ {
+ var unitOfWork = GetUnitOfWorkPerWebRequest();
+ unitOfWork.Rollback();
+ }
private IUnitOfWork GetUnitOfWorkPerWebRequest()
{
diff --git a/src/EmailMaker.WebsiteCore/Middleware/WindsorRegistrationExtensions.cs b/src/EmailMaker.WebsiteCore/Middleware/WindsorRegistrationExtensions.cs
new file mode 100644
index 0000000..14e1a3b
--- /dev/null
+++ b/src/EmailMaker.WebsiteCore/Middleware/WindsorRegistrationExtensions.cs
@@ -0,0 +1,30 @@
+using Castle.MicroKernel.Registration;
+using Castle.Windsor;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace EmailMaker.WebsiteCore
+{
+ public static class WindsorRegistrationExtensions
+ {
+ // method taken from https://github.com/fir3pho3nixx/Windsor/blob/aspnet-core-windsor-final/src/Castle.Facilities.AspNetCore/WindsorRegistrationExtensions.cs
+ // this version allows to pass parameters into the middleware
+ public static void UseMiddlewareFromWindsor(this IApplicationBuilder app, IWindsorContainer container, object argumentsAsAnonymousType)
+ where T : class, IMiddleware
+ {
+ container.Register(Component.For());
+ app.Use(async (context, next) =>
+ {
+ var resolve = container.Resolve(argumentsAsAnonymousType);
+ try
+ {
+ await resolve.InvokeAsync(context, async (ctx) => await next());
+ }
+ finally
+ {
+ container.Release(resolve);
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/EmailMaker.WebsiteCore/Startup.cs b/src/EmailMaker.WebsiteCore/Startup.cs
index e8bc988..ab594ab 100644
--- a/src/EmailMaker.WebsiteCore/Startup.cs
+++ b/src/EmailMaker.WebsiteCore/Startup.cs
@@ -4,7 +4,6 @@
using System.Data.SQLite;
using System.IO;
using System.Reflection;
-using System.Transactions;
using Castle.Facilities.AspNetCore;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
@@ -37,7 +36,7 @@
namespace EmailMaker.WebsiteCore
{
- public class Startup
+ public class Startup
{
private readonly WindsorContainer _windsorContainer = new WindsorContainer();
@@ -68,9 +67,6 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
- app.UseMiddlewareFromWindsor(_windsorContainer);
- //app.UseMiddlewareFromWindsor(_windsorContainer);
-
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
@@ -80,6 +76,9 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
app.UseExceptionHandler("/Home/Error");
}
+ app.UseMiddlewareFromWindsor(_windsorContainer, new { isolationLevel = IsolationLevel.ReadCommitted });
+ //app.UseMiddlewareFromWindsor(_windsorContainer, new { isolationLevel = IsolationLevel.ReadCommitted });
+
app.UseStaticFiles();
//app.UseAuthentication();
@@ -118,8 +117,8 @@ private void _RegisterApplicationComponents()
void _registerTransactionScopeStoragePerWebRequest()
{
_windsorContainer.Register(
- Component.For>()
- .ImplementedBy>()
+ Component.For>()
+ .ImplementedBy>()
.LifestyleScoped());
}