如何使用Mapster映射JsonPatchDocument ?



我有我的模型:

public class Membership  
{
[Key]
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MinLength(3)]
[MaxLength(30)]
public string Name { get; set; }
[Required] public int PeriodType { get; set; }

[Required] public int Duration { get; set; }

[Required] public int TerminationPeriod { get; set; }

[Required] public float InstallmentPrice { get; set; }
}

和我的Dto:

public class MembershipDto
{
public int Id { get; private set; }

public string Name { get; set; }
public int PeriodType { get; set; }

public int Duration { get; set; }

public int TerminationPeriod { get; set; }

public float InstallmentPrice { get; set; }
}

我使用实体框架和JsonPatchDocument在我的API中进行PATCH操作,代码如下:

public async Task<MembershipDto> Handle(EditMembershipCommand request, CancellationToken cancellationToken)
{
var membershipEntity = await _dbContext
.Memberships
.SingleOrDefaultAsync(m => m.Id == request.Id);
if (membershipEntity is null)
throw new NullReferenceException($"Membership [Id: {request.Id}] not found");
var editedMembership = request.NewMembershipDto.Adapt<JsonPatchDocument<Membership>>(); //request.NewMembershipDto is type of JsonPatchDocument<MembershipDto>
editedMembership.ApplyTo(membershipEntity, ModelState);
_ = await _dbContext.SaveChangesAsync();
var membershipDto = editedMembership.Adapt<MembershipDto>();
return membershipDto;
}

作为输出,我得到以下信息:

ProblemDetails.ProblemDetailsMiddleware[1]
An unhandled exception has occurred while executing the request.
Mapster.CompileException: Error while compiling
source=Microsoft.AspNetCore.JsonPatch.JsonPatchDocument`1[AgreementApi.Dtos.MembershipDto]
destination=Microsoft.AspNetCore.JsonPatch.JsonPatchDocument`1[AgreementApi.Models.Membership]
type=Map
---> Mapster.CompileException: Error while compiling
source=Newtonsoft.Json.Serialization.IContractResolver
destination=Newtonsoft.Json.Serialization.IContractResolver
type=Map
---> System.InvalidOperationException: No default constructor for type 'IContractResolver', please use 'ConstructUsing' or 'MapWith'
at Mapster.Utils.DynamicTypeGenerator.CreateTypeForInterface(Type interfaceType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Mapster.Utils.DynamicTypeGenerator.GetTypeForInterface(Type interfaceType)
at Mapster.Adapters.RecordTypeAdapter.CreateInstantiationExpression(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInstantiationExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.RecordTypeAdapter.CreateInlineExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInlineExpressionBody(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateAdaptFunc(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
--- End of inner exception stack trace ---
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateInlineMapExpression(Type sourceType, Type destinationType, MapType mapType, CompileContext context, MemberMapping mapping)
at Mapster.Adapters.BaseAdapter.CreateAdaptExpressionCore(Expression source, Type destinationType, CompileArgument arg, MemberMapping mapping, Expression destination)
at Mapster.Adapters.BaseAdapter.CreateAdaptExpression(Expression source, Type destinationType, CompileArgument arg, MemberMapping mapping, Expression destination)
at Mapster.Adapters.ClassAdapter.CreateInlineExpression(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateInlineExpressionBody(Expression source, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
at Mapster.Adapters.BaseAdapter.CreateAdaptFunc(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
--- End of inner exception stack trace ---
at Mapster.TypeAdapterConfig.CreateMapExpression(CompileArgument arg)
at Mapster.TypeAdapterConfig.CreateMapExpression(TypeTuple tuple, MapType mapType)
at Mapster.TypeAdapterConfig.CreateDynamicMapExpression(TypeTuple tuple)
at Mapster.TypeAdapterConfig.<GetDynamicMapFunction>b__66_0[TDestination](TypeTuple tuple)
at Mapster.TypeAdapterConfig.<>c__DisplayClass55_0`1.<AddToHash>b__0(TypeTuple types)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Mapster.TypeAdapterConfig.AddToHash[T](ConcurrentDictionary`2 hash, TypeTuple key, Func`2 func)
at Mapster.TypeAdapterConfig.GetDynamicMapFunction[TDestination](Type sourceType)
at Mapster.TypeAdapter.Adapt[TDestination](Object source, TypeAdapterConfig config)
at Mapster.TypeAdapter.Adapt[TDestination](Object source)
at Fitverse.AgreementApi.Handlers.EditMembershipHandler.Handle(EditMembershipCommand request, CancellationToken cancellationToken) in /Users/wonsu/Repositories/Fitverse/Fitverse.AgreementApi/Handlers/EditMembershipHandler.cs:line 34
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
at Fitverse.AgreementApi.Controllers.SettingsController.EditMembership(Int32 id, JsonPatchDocument`1 membershipDto) in /Users/wonsu/Repositories/Fitverse/Fitverse.AgreementApi/Controllers/SettingsController.cs:line 52
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Hellang.Middleware.ProblemDetails.ProblemDetailsMiddleware.Invoke(HttpContext context)

我知道问题出在这行代码中:

var editedMembership = request.NewMembershipDto.Adapt<JsonPatchDocument<Membership>>();

但是我不知道如何更改它以正确地将其映射到所需的类型。你能帮我吗?:)

我知道,在结束时,我可能应该从DB再次获得成员资格,映射它并返回它,而不仅仅是映射editedMembership,但我将适合它后处理这个映射问题。

添加IContractResolver的映射有助于解决这个问题。

private static TypeAdapterConfig GetConfiguredMappingConfig()
{
var config = TypeAdapterConfig.GlobalSettings;
IList<IRegister> registers = config.Scan(Assembly.GetExecutingAssembly());
config.Apply(registers);
config.NewConfig<IContractResolver, IContractResolver>()
.ConstructUsing(src => new DefaultContractResolver());
return config;
}

相关内容

  • 没有找到相关文章

最新更新