添加工作单元

This commit is contained in:
黎明
2022-12-26 14:19:12 +08:00
parent c964b98240
commit ec06d30d59
15 changed files with 297 additions and 14 deletions

View File

@@ -16,6 +16,7 @@ using Yi.Framework.Job;
using Yi.Framework.Language;
using Yi.Framework.Model.Models;
using Yi.Framework.Repository;
using Yi.Framework.Uow.Interceptors;
using Yi.Framework.WebCore;
using Yi.Framework.WebCore.AttributeExtend;
using Yi.Framework.WebCore.AuthorizationPolicy;
@@ -62,10 +63,10 @@ namespace Yi.Framework.ApiMicroservice.Controllers
ThumbnailSharpInvoer thumbnailSharpInvoer,
CacheInvoker cacheInvoker) =>
(_logger,_iUserService, _iRoleService, _quartzInvoker, _hub, _local, _thumbnailSharpInvoer, _cacheDb) =
(_logger, _iUserService, _iRoleService, _quartzInvoker, _hub, _local, _thumbnailSharpInvoer, _cacheDb) =
(logger, iUserService, iRoleService, quartzInvoker, hub, local, thumbnailSharpInvoer, cacheInvoker);
/// <summary>
/// swagger跳转
@@ -109,6 +110,15 @@ namespace Yi.Framework.ApiMicroservice.Controllers
return Result.Success().SetData(await _iUserService.DbTest());
}
[HttpGet]
public async Task<Result> TestUnitOfWork()
{
var userId = await _iUserService.AddInfo(new DTOModel.UserInfoDto { User = new UserEntity { Address = "", UserName = "lisi", Password = "123456" }.BuildPassword() });
throw new ApplicationException("测试uow");
await _iRoleService._repository.InsertReturnSnowflakeIdAsync(new RoleEntity { RoleName = "测试", RoleCode = "tt" });
return Result.Success();
}
/// <summary>
/// 执行Sql返回
/// </summary>

View File

@@ -18,6 +18,9 @@ using Yi.Framework.WebCore.LogExtend;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.AspNetCore.Mvc.Controllers;
using Yi.Framework.WebCore.AutoFacExtend;
using AspectCore.Extensions.DependencyInjection;
using AspectCore.Extensions.Hosting;
using Yi.Framework.Uow.Interceptors;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddCommandLine(args);
@@ -31,6 +34,9 @@ builder.Host.ConfigureAppConfiguration((hostBuilderContext, configurationBuilder
#endregion
configurationBuilder.AddApolloService("Yi");
});
builder.Services.AddUnitOfWork();
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
@@ -47,6 +53,7 @@ builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
#endregion
containerBuilder.AddAutoIocService("Yi.Framework.Repository", "Yi.Framework.Service");
});
////<2F><><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD><EBA3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>mvcģ<63><C4A3>ת<EFBFBD>Ӹ<EFBFBD>ioc
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
@@ -154,6 +161,7 @@ builder.Services.AddHttpContextAccessor();
#endregion
builder.Services.AddSingleton<ThumbnailSharpInvoer>();
#region
//ȫ<><C8AB><EFBFBD><EFBFBD><EFBFBD>ó<EFBFBD>ʼ<EFBFBD><CABC>ֵ
#endregion
@@ -237,6 +245,5 @@ app.UseEndpoints(endpoints =>
endpoints.MapHub<MainHub>("/api/hub/main");
endpoints.MapControllers();
});
//׼<><D7BC><EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><D3B6>
app.Run();

View File

@@ -21,6 +21,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspectCore.Extensions.Hosting" Version="2.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Uow\Yi.Framework.Uow.csproj" />
<ProjectReference Include="..\Yi.Framework.WebCore\Yi.Framework.WebCore.csproj" />
</ItemGroup>

View File

@@ -23,7 +23,7 @@ namespace Yi.Framework.Model.Models
/// <summary>
/// 构建密码MD5盐值加密
/// </summary>
public void BuildPassword(string password = null)
public UserEntity BuildPassword(string password = null)
{
//如果不传值那就把自己的password当作传进来的password
if (password == null)
@@ -32,6 +32,7 @@ namespace Yi.Framework.Model.Models
}
this.Salt = Common.Helper.MD5Helper.GenerateSalt();
this.Password = Common.Helper.MD5Helper.SHA2Encode(password, this.Salt);
return this;
}
/// <summary>

View File

@@ -0,0 +1,13 @@
using System.Data;
namespace Yi.Framework.Uow
{
public interface IUnitOfWork : IDisposable
{
public void Init(bool isTransactional, IsolationLevel? isolationLevel, int? timeout);
public void BeginTran();
public void CommitTran();
public void RollbackTran();
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Uow.Interceptors
{
public class UnitOfWorkAttribute : Attribute// : AbstractInterceptorAttribute
{
public UnitOfWorkAttribute(bool isTransactional = true)
{
IsTransactional = isTransactional;
}
public UnitOfWorkAttribute(IsolationLevel isolationLevel, bool isTransactional = true) : this(isTransactional)
{
IsolationLevel = isolationLevel;
}
public UnitOfWorkAttribute(IsolationLevel isolationLevel, int timeout, bool isTransactional = true) : this(isolationLevel, isTransactional)
{
Timeout = timeout;
}
public bool IsTransactional { get; }
public IsolationLevel? IsolationLevel { get; }
/// <summary>
/// Milliseconds
/// </summary>
public int? Timeout { get; }
public bool IsDisabled { get; }
//public override Task Invoke(AspectContext context, AspectDelegate next)
//{
// if (IsTransactional)
// {
// ServiceLocator.in.getservice()
// }
//}
}
}

View File

@@ -0,0 +1,78 @@
using Castle.DynamicProxy;
using Nest;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Uow.Interceptors
{
public class UnitOfWorkInterceptor : IInterceptor
{
private readonly IUnitOfWork _unitOfWork;
public UnitOfWorkInterceptor(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void Intercept(IInvocation invocation)
{
if (!IsUnitOfWorkMethod(invocation.Method, out var uowAttr))
{
invocation.Proceed();
return;
}
try
{
_unitOfWork.BeginTran();
//执行被拦截的方法
invocation.Proceed();
_unitOfWork.CommitTran();
}
catch (Exception ex)
{
_unitOfWork.RollbackTran();
throw ex;
}
}
public static bool IsUnitOfWorkMethod( MethodInfo methodInfo,out UnitOfWorkAttribute unitOfWorkAttribute)
{
//Method declaration
var attrs = methodInfo.GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();
if (attrs.Any())
{
unitOfWorkAttribute = attrs.First();
return !unitOfWorkAttribute.IsDisabled;
}
if (methodInfo.DeclaringType != null)
{
//Class declaration
attrs = methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();
if (attrs.Any())
{
unitOfWorkAttribute = attrs.First();
return !unitOfWorkAttribute.IsDisabled;
}
////Conventional classes
//if (typeof(IUnitOfWorkEnabled).GetTypeInfo().IsAssignableFrom(methodInfo.DeclaringType))
//{
// unitOfWorkAttribute = null;
// return true;
//}
}
unitOfWorkAttribute = null;
return false;
}
}
}

View File

@@ -0,0 +1,21 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Uow;
using Yi.Framework.Uow.Interceptors;
namespace Microsoft.Extensions.DependencyInjection
{
public static class UowIServiceCollectionExtensions
{
public static void AddUnitOfWork(this IServiceCollection services)
{
services.AddScoped(typeof(IUnitOfWork), typeof(UnitOfWork));
services.AddSingleton<UnitOfWorkInterceptor>();
}
}
}

View File

@@ -0,0 +1,75 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Uow
{
public class UnitOfWork : IUnitOfWork
{
public bool IsTransactional { get; protected set; }
public IsolationLevel? IsolationLevel { get; protected set; }
/// <summary>
/// Milliseconds
/// </summary>
public int? Timeout { get; protected set; }
public void Init(bool isTransactional, IsolationLevel? isolationLevel, int? timeout)
{
IsTransactional = isTransactional;
IsolationLevel = isolationLevel;
Timeout = timeout;
}
public ISqlSugarClient SugarClient { get; set; }
/// <summary>
/// 因为sqlsugarclient的生命周期是作用域的也就是说一个请求线程内是共用一个client暂时先直接注入
/// </summary>
/// <param name="sqlSugarClient"></param>
public UnitOfWork(ISqlSugarClient sqlSugarClient)
{
this.SugarClient = sqlSugarClient;
}
public void Dispose()
{
SugarClient?.Dispose();
SugarClient?.Close();
}
public void BeginTran()
{
if (IsTransactional)
{
if (IsolationLevel.HasValue)
{
SugarClient.Ado.BeginTran(IsolationLevel.Value);
}
else
{
SugarClient.Ado.BeginTran();
}
}
}
public void CommitTran()
{
if (IsTransactional)
SugarClient.Ado.CommitTran();
}
public void RollbackTran()
{
if (IsTransactional)
SugarClient.Ado.RollbackTran();
}
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Castle.Core" Version="5.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Repository\Yi.Framework.Repository.csproj" />
</ItemGroup>
</Project>

View File

@@ -15,6 +15,7 @@ using Yi.Framework.Interface;
using Yi.Framework.Job;
using Yi.Framework.Repository;
using Yi.Framework.Service;
using Yi.Framework.Uow.Interceptors;
using Yi.Framework.WebCore.AutoFacExtend;
using Module = Autofac.Module;
@@ -48,7 +49,8 @@ namespace Yi.Framework.WebCore.AutoFacExtend
containerBuilder.RegisterAssemblyTypes(assemblysServices)
.AsImplementedInterfaces()
.InstancePerLifetimeScope()
.EnableInterfaceInterceptors();
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(UnitOfWorkInterceptor));
///反射注册任务调度层
var assemblysJob = GetDll("Yi.Framework.Job.dll");

View File

@@ -1,5 +1,6 @@

using Autofac;
using Autofac.Extras.DynamicProxy;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
@@ -9,6 +10,7 @@ using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Common.Attribute;
using Yi.Framework.Uow.Interceptors;
namespace Yi.Framework.WebCore.MiddlewareExtend
{
@@ -44,41 +46,41 @@ namespace Yi.Framework.WebCore.MiddlewareExtend
case LifeTime.Singleton:
if (type.IsGenericType)
{
build.RegisterGeneric(type).As(serviceType).SingleInstance();
build.RegisterGeneric(type).As(serviceType).SingleInstance().EnableInterfaceInterceptors();
}
else
{
build.RegisterType(type).As(serviceType).SingleInstance();
build.RegisterType(type).As(serviceType).SingleInstance().EnableInterfaceInterceptors();
}
break;
case LifeTime.Scoped:
if (type.IsGenericType)
{
build.RegisterGeneric(type).As(serviceType).InstancePerLifetimeScope();
build.RegisterGeneric(type).As(serviceType).InstancePerLifetimeScope().EnableInterfaceInterceptors();
}
else
{
build.RegisterType(type).As(serviceType).InstancePerLifetimeScope();
build.RegisterType(type).As(serviceType).InstancePerLifetimeScope().EnableInterfaceInterceptors();
}
break;
case LifeTime.Transient:
if (type.IsGenericType)
{
build.RegisterGeneric(type).As(serviceType).InstancePerDependency();
build.RegisterGeneric(type).As(serviceType).InstancePerDependency().EnableInterfaceInterceptors();
}
else
{
build.RegisterType(type).As(serviceType).InstancePerDependency();
build.RegisterType(type).As(serviceType).InstancePerDependency().EnableInterfaceInterceptors();
}
break;
default:
if (type.IsGenericType)
{
build.RegisterGeneric(type).As(serviceType).InstancePerDependency();
build.RegisterGeneric(type).As(serviceType).InstancePerDependency().EnableInterfaceInterceptors();
}
else
{
build.RegisterType(type).As(serviceType).InstancePerDependency();
build.RegisterType(type).As(serviceType).InstancePerDependency().EnableInterfaceInterceptors();
}
break;
}

View File

@@ -36,6 +36,7 @@
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
<ProjectReference Include="..\Yi.Framework.Service\Yi.Framework.Service.csproj" />
<ProjectReference Include="..\Yi.Framework.Uow\Yi.Framework.Uow.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -47,7 +47,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.WeChatPay", "Y
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Template", "Yi.Framework.Template\Yi.Framework.Template.csproj", "{A51E9091-3745-461A-A3CB-32598BF0DC77}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.XUnitTest", "Yi.Framework.XUnitTest\Yi.Framework.XUnitTest.csproj", "{88E3298A-135D-4D9C-B98D-41A2C4268385}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.XUnitTest", "Yi.Framework.XUnitTest\Yi.Framework.XUnitTest.csproj", "{88E3298A-135D-4D9C-B98D-41A2C4268385}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Uow", "Yi.Framework.Uow\Yi.Framework.Uow.csproj", "{657E4EA0-5A34-4D09-A39C-419C31E740FE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -127,6 +129,10 @@ Global
{88E3298A-135D-4D9C-B98D-41A2C4268385}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88E3298A-135D-4D9C-B98D-41A2C4268385}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88E3298A-135D-4D9C-B98D-41A2C4268385}.Release|Any CPU.Build.0 = Release|Any CPU
{657E4EA0-5A34-4D09-A39C-419C31E740FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{657E4EA0-5A34-4D09-A39C-419C31E740FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{657E4EA0-5A34-4D09-A39C-419C31E740FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{657E4EA0-5A34-4D09-A39C-419C31E740FE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -150,6 +156,7 @@ Global
{C307189D-C42C-4C09-BB65-5A386C9F182B} = {9ABAF6B1-6C02-498A-90A2-ABC1140CF89A}
{A51E9091-3745-461A-A3CB-32598BF0DC77} = {9ABAF6B1-6C02-498A-90A2-ABC1140CF89A}
{88E3298A-135D-4D9C-B98D-41A2C4268385} = {C90E38FB-69EA-4997-8B3A-2C71EFA65B2B}
{657E4EA0-5A34-4D09-A39C-419C31E740FE} = {DB2506F5-05FD-4E76-940E-41D7AA148550}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1ED77A6E-377F-4EEF-A3D0-D65C94657DAF}