diff --git a/Examples/aspnetcore_transaction/Controllers/HomeController.cs b/Examples/aspnetcore_transaction/Controllers/HomeController.cs index 75076486..4409056a 100644 --- a/Examples/aspnetcore_transaction/Controllers/HomeController.cs +++ b/Examples/aspnetcore_transaction/Controllers/HomeController.cs @@ -3,6 +3,7 @@ using FreeSql.DataAnnotations; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using System; using System.ComponentModel; using System.Linq; using System.Reflection; @@ -24,20 +25,21 @@ namespace aspnetcore_transaction.Controllers [HttpGet("1")] //[Transactional] - virtual public object Get([FromServices] BaseRepository repoSong, [FromServices] BaseRepository repoDetail, [FromServices] SongRepository repoSong2, + async public Task Get([FromServices] BaseRepository repoSong, [FromServices] BaseRepository repoDetail, [FromServices] SongRepository repoSong2, [FromServices] SongService serviceSong) { //repoSong.Insert(new Song()); //repoDetail.Insert(new Detail()); //repoSong2.Insert(new Song()); - serviceSong.Test1(); + //serviceSong.Test1(); + await serviceSong.Test11(); return "111"; } [HttpGet("2")] //[Transactional] - async virtual public Task GetAsync([FromServices] BaseRepository repoSong, [FromServices] BaseRepository repoDetail, [FromServices] SongRepository repoSong2, + async public Task GetAsync([FromServices] BaseRepository repoSong, [FromServices] BaseRepository repoDetail, [FromServices] SongRepository repoSong2, [FromServices] SongService serviceSong) { await serviceSong.Test2(); @@ -61,15 +63,21 @@ namespace aspnetcore_transaction.Controllers } [Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的 - public virtual void Test1() + public void Test1() { _repoSong.Insert(new Song()); _repoDetail.Insert(new Detail()); _repoSong2.Insert(new Song()); } + [Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的 + async public Task Test11() + { + await Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(t => + _repoSong.InsertAsync(new Song())); + } [Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的 - async public virtual Task Test2() + async public Task Test2() { await _repoSong.InsertAsync(new Song()); await _repoDetail.InsertAsync(new Detail()); @@ -77,7 +85,7 @@ namespace aspnetcore_transaction.Controllers } [Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的 - async public virtual Task Test3() + async public Task Test3() { await _repoSong.InsertAsync(new Song()); await _repoDetail.InsertAsync(new Detail()); @@ -110,53 +118,4 @@ namespace aspnetcore_transaction.Controllers public int SongId { get; set; } public string Title { get; set; } } - - public static class IdleBusExtesions - { - static AsyncLocal AsyncLocalTenantId = new AsyncLocal(); - public static IdleBus ChangeTenant(this IdleBus ib, string tenantId) - { - AsyncLocalTenantId.Value = tenantId; - return ib; - } - public static IFreeSql Get(this IdleBus ib) => ib.Get(AsyncLocalTenantId.Value ?? "default"); - public static IBaseRepository GetRepository(this IdleBus ib) where T : class => ib.Get().GetRepository(); - - static void test() - { - IdleBus ib = null; //单例注入 - - var fsql = ib.Get(); //获取当前租户对应的 IFreeSql - - var fsql00102 = ib.ChangeTenant("00102").Get(); //切换租户,后面的操作都是针对 00102 - - var songRepository = ib.GetRepository(); - var detailRepository = ib.GetRepository(); - } - - public static IServiceCollection AddRepository(this IServiceCollection services, params Assembly[] assemblies) - { - services.AddScoped(typeof(IBaseRepository<>), typeof(YourDefaultRepository<>)); - services.AddScoped(typeof(BaseRepository<>), typeof(YourDefaultRepository<>)); - - services.AddScoped(typeof(IBaseRepository<,>), typeof(YourDefaultRepository<,>)); - services.AddScoped(typeof(BaseRepository<,>), typeof(YourDefaultRepository<,>)); - - if (assemblies?.Any() == true) - foreach (var asse in assemblies) - foreach (var repo in asse.GetTypes().Where(a => a.IsAbstract == false && typeof(IBaseRepository).IsAssignableFrom(a))) - services.AddScoped(repo); - - return services; - } - } - - class YourDefaultRepository : BaseRepository where T : class - { - public YourDefaultRepository(IdleBus ib) : base(ib.Get(), null, null) { } - } - class YourDefaultRepository : BaseRepository where T : class - { - public YourDefaultRepository(IdleBus ib) : base(ib.Get(), null, null) { } - } } diff --git a/Examples/aspnetcore_transaction/FodyWeavers.xml b/Examples/aspnetcore_transaction/FodyWeavers.xml new file mode 100644 index 00000000..a6a2edf1 --- /dev/null +++ b/Examples/aspnetcore_transaction/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Examples/aspnetcore_transaction/FodyWeavers.xsd b/Examples/aspnetcore_transaction/FodyWeavers.xsd new file mode 100644 index 00000000..f35a69b7 --- /dev/null +++ b/Examples/aspnetcore_transaction/FodyWeavers.xsd @@ -0,0 +1,26 @@ + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/Examples/aspnetcore_transaction/Program.cs b/Examples/aspnetcore_transaction/Program.cs index 24fcc6bf..ffebf9c9 100644 --- a/Examples/aspnetcore_transaction/Program.cs +++ b/Examples/aspnetcore_transaction/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -22,6 +22,7 @@ namespace aspnetcore_transaction { webBuilder.UseStartup(); }) - .UseServiceProviderFactory(new FreeSql.DynamicProxyServiceProviderFactory()); + //.UseServiceProviderFactory(new FreeSql.DynamicProxyServiceProviderFactory()) + ; } } diff --git a/Examples/aspnetcore_transaction/Startup.cs b/Examples/aspnetcore_transaction/Startup.cs index 33903efa..c6d52bec 100644 --- a/Examples/aspnetcore_transaction/Startup.cs +++ b/Examples/aspnetcore_transaction/Startup.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -52,6 +52,12 @@ namespace aspnetcore_transaction Console.OutputEncoding = Encoding.GetEncoding("GB2312"); Console.InputEncoding = Encoding.GetEncoding("GB2312"); + app.Use(async (context, next) => + { + TransactionalAttribute.SetServiceProvider(context.RequestServices); + await next(); + }); + app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" }); app.UseDeveloperExceptionPage(); app.UseRouting(); diff --git a/Examples/aspnetcore_transaction/TransactionalAttribute.cs b/Examples/aspnetcore_transaction/TransactionalAttribute.cs index 875e03df..5c9b5a53 100644 --- a/Examples/aspnetcore_transaction/TransactionalAttribute.cs +++ b/Examples/aspnetcore_transaction/TransactionalAttribute.cs @@ -1,54 +1,43 @@ using FreeSql; using Microsoft.AspNetCore.Mvc.Filters; +using Rougamo.Context; using System; using System.Collections.Generic; using System.Data; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace FreeSql { - /// - /// 使用事务执行,请查看 Program.cs 代码开启动态代理 - /// [AttributeUsage(AttributeTargets.Method)] - public class TransactionalAttribute : DynamicProxyAttribute, IActionFilter + public class TransactionalAttribute : Rougamo.MoAttribute { public Propagation Propagation { get; set; } = Propagation.Required; - public IsolationLevel IsolationLevel { get => _IsolationLevelPriv.Value; set => _IsolationLevelPriv = value; } - IsolationLevel? _IsolationLevelPriv; + public IsolationLevel IsolationLevel { get => m_IsolationLevel.Value; set => m_IsolationLevel = value; } + IsolationLevel? m_IsolationLevel; + + static AsyncLocal m_ServiceProvider = new AsyncLocal(); + public static void SetServiceProvider(IServiceProvider serviceProvider) => + m_ServiceProvider.Value = serviceProvider; - [DynamicProxyFromServices] -#pragma warning disable IDE0044 // 添加只读修饰符 - UnitOfWorkManager _uowManager; -#pragma warning restore IDE0044 // 添加只读修饰符 IUnitOfWork _uow; - - public override Task Before(DynamicProxyBeforeArguments args) => OnBefore(_uowManager); - public override Task After(DynamicProxyAfterArguments args) => OnAfter(args.Exception); - - //这里是为了 controller - public void OnActionExecuting(ActionExecutingContext context) => OnBefore(context.HttpContext.RequestServices.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager); - public void OnActionExecuted(ActionExecutedContext context) => OnAfter(context.Exception); - - - Task OnBefore(UnitOfWorkManager uowm) + public override void OnEntry(MethodContext context) { - _uow = uowm.Begin(this.Propagation, this._IsolationLevelPriv); - return Task.FromResult(false); + var uowManager = m_ServiceProvider.Value.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager; + _uow = uowManager.Begin(this.Propagation, this.m_IsolationLevel); } - Task OnAfter(Exception ex) + public override void OnExit(MethodContext context) { try { - if (ex == null) _uow.Commit(); + if (context.Exception == null) _uow.Commit(); else _uow.Rollback(); } finally { _uow.Dispose(); } - return Task.FromResult(false); } } } diff --git a/Examples/aspnetcore_transaction/TransactionalAttribute02.cs b/Examples/aspnetcore_transaction/TransactionalAttribute02.cs new file mode 100644 index 00000000..fb4629ee --- /dev/null +++ b/Examples/aspnetcore_transaction/TransactionalAttribute02.cs @@ -0,0 +1,54 @@ +//using FreeSql; +//using Microsoft.AspNetCore.Mvc.Filters; +//using System; +//using System.Collections.Generic; +//using System.Data; +//using System.Text; +//using System.Threading.Tasks; + +//namespace FreeSql +//{ +// /// +// /// 使用事务执行,请查看 Program.cs 代码开启动态代理 +// /// +// [AttributeUsage(AttributeTargets.Method)] +// public class TransactionalAttribute : DynamicProxyAttribute, IActionFilter +// { +// public Propagation Propagation { get; set; } = Propagation.Required; +// public IsolationLevel IsolationLevel { get => _IsolationLevelPriv.Value; set => _IsolationLevelPriv = value; } +// IsolationLevel? _IsolationLevelPriv; + +// [DynamicProxyFromServices] +//#pragma warning disable IDE0044 // 添加只读修饰符 +// UnitOfWorkManager _uowManager; +//#pragma warning restore IDE0044 // 添加只读修饰符 +// IUnitOfWork _uow; + +// public override Task Before(DynamicProxyBeforeArguments args) => OnBefore(_uowManager); +// public override Task After(DynamicProxyAfterArguments args) => OnAfter(args.Exception); + +// //这里是为了 controller +// public void OnActionExecuting(ActionExecutingContext context) => OnBefore(context.HttpContext.RequestServices.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager); +// public void OnActionExecuted(ActionExecutedContext context) => OnAfter(context.Exception); + + +// Task OnBefore(UnitOfWorkManager uowm) +// { +// _uow = uowm.Begin(this.Propagation, this._IsolationLevelPriv); +// return Task.FromResult(false); +// } +// Task OnAfter(Exception ex) +// { +// try +// { +// if (ex == null) _uow.Commit(); +// else _uow.Rollback(); +// } +// finally +// { +// _uow.Dispose(); +// } +// return Task.FromResult(false); +// } +// } +//} diff --git a/Examples/aspnetcore_transaction/aspnetcore_transaction.csproj b/Examples/aspnetcore_transaction/aspnetcore_transaction.csproj index f385c178..32a8331c 100644 --- a/Examples/aspnetcore_transaction/aspnetcore_transaction.csproj +++ b/Examples/aspnetcore_transaction/aspnetcore_transaction.csproj @@ -11,6 +11,7 @@ + diff --git a/Examples/aspnetcore_transaction/aspnetcore_transaction.xml b/Examples/aspnetcore_transaction/aspnetcore_transaction.xml index 8d78a341..d301a332 100644 --- a/Examples/aspnetcore_transaction/aspnetcore_transaction.xml +++ b/Examples/aspnetcore_transaction/aspnetcore_transaction.xml @@ -9,10 +9,5 @@ 自增 - - - 使用事务执行,请查看 Program.cs 代码开启动态代理 - - diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 537315e2..26522f10 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -800,5 +800,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + +