
add optional parameters in dto is hight frequency
i don't want to update .Application.Contracts package in many refrenced projects every time when i add a new property in dto becuse it is no [required] parameter
You can also try it with the latest ABP.
reproduce Steps:
abp new ApiA -o ApiA&&abp new ApiB -o ApiB, ApiA is basic microservice.public interface IApiAAppService : IApplicationService
{
public Task<List<string>> GetListAsync(ApiAListInputDto input);
}
and Dto
public class ApiAListInputDto
{
public string ParameterOne { get; set; }
}
,after build we get the output ApiA.Application.Contract.nupkg-v1.0.0
3, Add ApiA.Application.Contract.nupkg-v1.0.0 in ApiB.Application.proj,Enable dynamic proxy client to request ApiA, everything is ok.
public class ApiBAppService : ApplicationService
{
private readonly IApiAAppService _apiAAppService;
protected ApiBAppService(IApiAAppService apiAAppService)
{
_apiAAppService = apiAAppService;
LocalizationResource = typeof(ApiBResource);
}
public async Task<List<string>> GetAListAsync()
{
return await _apiAAppService.GetListAsync(new ApiAListInputDto() {ParameterOne = "one"});
}
}
4,Add new parameter in ApiAListInputDto
public class ApiAListInputDto
{
public string ParameterOne { get; set; }
// add new params that is not apply [Required]
public string ParameterTwo { get; set; }
}
5,Restart ApiA and ApiB, request ApiBAppService.GetAListAsync again 锛孉bp throw Exception:
2020-09-28 14:22:18.164 +08:00 [ERR] Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
at Volo.Abp.Reflection.ReflectionHelper.GetValueByPath(Object obj, Type objectType, String propertyPath)
at Volo.Abp.Http.Client.DynamicProxying.HttpActionParameterHelper.FindParameterValue(IReadOnlyDictionary`2 methodArguments, ParameterApiDescriptionModel apiParameter)
at Volo.Abp.Http.Client.DynamicProxying.UrlBuilder.AddQueryStringParameters(StringBuilder urlBuilder, IList`1 actionParameters, IReadOnlyDictionary`2 methodArguments, ApiVersionInfo apiVersion)
at Volo.Abp.Http.Client.DynamicProxying.UrlBuilder.GenerateUrlWithParameters(ActionApiDescriptionModel action, IReadOnlyDictionary`2 methodArguments, ApiVersionInfo apiVersion)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.MakeRequestAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.MakeRequestAndGetResultAsync[T](IAbpMethodInvocation invocation)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.GetResultAsync(Task task, Type resultType)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
Have you tried using ProjectReferenceinstead of nupkg?
You can also share the source code of your projects.
ProjectReference works, because the latest dto is synchronized when the service restarted, but it doesn't expose critical issues. In microservice scenarios, infrastructure services are usually deployed independently and keep API downward compatibility. If it is not for breking change, many other dependencies do not need to care about this change and are not required to be forced to update the latest version of dto.
The frequency of dto parameter changes is too high. If all dependent services need to be updated every time, the cost is very high.
I tested dynamic api proxy use IIdentityUserAppService,and add PackageReference Volo.Abp.Identity.HttpApi.Client ,but throw a exception.
method:
public async Task<IdentityUserDto> GetIdentityUser(string name)
{
return await IdentityUserAppService.FindByUsernameAsync(username: name);
}
exceptions:
Volo.Abp.AbpException: Missing path parameter value for userName (userName)
at Volo.Abp.Http.Client.DynamicProxying.UrlBuilder.ReplacePathVariables(StringBuilder urlBuilder, IList`1 actionParameters, IReadOnlyDictionary`2 methodArguments, ApiVersionInfo apiVersion)
at Volo.Abp.Http.Client.DynamicProxying.UrlBuilder.GenerateUrlWithParameters(ActionApiDescriptionModel action, IReadOnlyDictionary`2 methodArguments, ApiVersionInfo apiVersion)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.MakeRequestAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.MakeRequestAndGetResultAsync[T](IAbpMethodInvocation invocation)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.GetResultAsync(Task task, Type resultType)
at Volo.Abp.Http.Client.DynamicProxying.DynamicHttpProxyInterceptor`1.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.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.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
@seayxu Please create a new issue.
Most helpful comment
ProjectReferenceworks, because the latest dto is synchronized when the service restarted, but it doesn't expose critical issues. In microservice scenarios, infrastructure services are usually deployed independently and keep API downward compatibility. If it is not for breking change, many other dependencies do not need to care about this change and are not required to be forced to update the latest version of dto.The frequency of dto parameter changes is too high. If all dependent services need to be updated every time, the cost is very high.
This is my source code