public void CreateValidationProblemDetails_DefaultValues() { // Act var modelState = new ModelStateDictionary(); modelState.AddModelError("some-key", "some-value"); var problemDetails = Factory.CreateValidationProblemDetails(GetHttpContext(), modelState); // Assert Assert.Equal(400, problemDetails.Status); Assert.Equal("One or more validation errors occurred.", problemDetails.Title); Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.5.1", problemDetails.Type); Assert.Null(problemDetails.Instance); Assert.Null(problemDetails.Detail); Assert.Collection( problemDetails.Extensions, kvp => { Assert.Equal("traceId", kvp.Key); Assert.Equal("some-trace", kvp.Value); }); Assert.Collection( problemDetails.Errors, kvp => { Assert.Equal("some-key", kvp.Key); Assert.Equal(new[] { "some-value" }, kvp.Value); }); }
public Task OnExceptionAsync(ExceptionContext context) { var errors = new ModelStateDictionary(); switch (context.Exception) { case EntityNotFoundException exception: errors.AddModelError(exception.ParamName, exception.Message); context.Result = new NotFoundObjectResult(_pdFactory.CreateValidationProblemDetails(context.HttpContext, errors, StatusCodes.Status404NotFound)) { StatusCode = StatusCodes.Status404NotFound }; break; case InvalidArgumentException exception: errors.AddModelError(exception.ParamName, exception.Message); context.Result = new BadRequestObjectResult(_pdFactory.CreateValidationProblemDetails(context.HttpContext, errors, StatusCodes.Status400BadRequest)); break; case EntityExistException exception: errors.AddModelError(exception.ParamName, exception.Message); context.Result = new UnprocessableEntityObjectResult(_pdFactory.CreateValidationProblemDetails(context.HttpContext, errors, StatusCodes.Status422UnprocessableEntity)) { StatusCode = StatusCodes.Status422UnprocessableEntity }; break; case InvalidUserInputException exception: context.Result = new UnprocessableEntityObjectResult(_pdFactory.CreateProblemDetails(context.HttpContext, StatusCodes.Status422UnprocessableEntity, null, null, exception.Message)); break; case InvalidOperationException exception: context.Result = new UnprocessableEntityObjectResult(_pdFactory.CreateProblemDetails(context.HttpContext, StatusCodes.Status422UnprocessableEntity, null, null, exception.Message)); break; case InternalException exception: goto default; default: var message = ""; if (!_env.IsProduction()) { message += $"{context.Exception.Message}: {context.Exception.InnerException?.Message}"; } context.Result = new ObjectResult(_pdFactory.CreateProblemDetails(context.HttpContext, StatusCodes.Status500InternalServerError, null, null, $"Unhandled exception. {message}")) { StatusCode = StatusCodes.Status500InternalServerError }; break; } return(Task.CompletedTask); }
private ProblemDetails HandleException(ExceptionContext context) { switch (context.Exception) { case ArgumentException argumentException: { if (!string.IsNullOrEmpty(argumentException.ParamName)) { context.ModelState.AddModelError(argumentException.ParamName, argumentException.Message); } var problemDetails = _problemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState); problemDetails.Detail = argumentException.Message; return(problemDetails); } case InvalidOperationException invalidOperationException: { var problemDetails = _problemDetailsFactory.CreateProblemDetails(context.HttpContext); problemDetails.Detail = invalidOperationException.Message; return(problemDetails); } case ValidationException validationException: { foreach (var item in validationException.Errors) { context.ModelState.AddModelError(item.PropertyName, item.ErrorMessage); } var problemDetails = _problemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState); problemDetails.Detail = "Your request cannot pass our validations. Sorry"; return(problemDetails); } case ApiErrorException apiErrorException: { var detail = apiErrorException.Body.Error.Message; var problemDetails = _problemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState); problemDetails.Detail = detail; return(problemDetails); } default: return(default); } }
static IActionResult problemDetailsInvalidModelStateResponse( ProblemDetailsFactory problemDetailsFactory, ActionContext context ) { var problemDetails = problemDetailsFactory.CreateValidationProblemDetails( context.HttpContext, context.ModelState ); ObjectResult result; if (problemDetails.Status == 400) { // For compatibility with 2.x, continue producing BadRequestObjectResult instances if the status code is 400. result = new BadRequestObjectResult(problemDetails); } else { result = new ObjectResult(problemDetails) { StatusCode = problemDetails.Status }; } result.ContentTypes.Add("application/problem+json"); result.ContentTypes.Add("application/problem+xml"); return(result); }
public static void UseCustomInvalidModelUnprocessableEntityResponse(this ApiBehaviorOptions options) { options.InvalidModelStateResponseFactory = (actionContext) => { ProblemDetailsFactory problemFactory = actionContext.HttpContext.RequestServices.GetRequiredService <ProblemDetailsFactory>(); ProblemDetails problemDetails = problemFactory.CreateValidationProblemDetails(actionContext.HttpContext, actionContext.ModelState); problemDetails.Instance = actionContext.HttpContext.Request.Path; problemDetails.Detail = "See errors property for additional details."; var actionExecutingContext = actionContext as ActionExecutingContext; if (actionContext.ModelState.ErrorCount != 0 && (actionContext is ControllerContext || actionContext.ActionDescriptor.Parameters.Count == actionExecutingContext.ActionArguments.Count)) { problemDetails.Title = "One or more validation errors occured."; problemDetails.Status = StatusCodes.Status422UnprocessableEntity; problemDetails.Instance = $"{actionContext.HttpContext.Request.PathBase}/modelvalidationerror"; return(new UnprocessableEntityObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); } problemDetails.Title = "One or more errors occured on the input"; problemDetails.Status = StatusCodes.Status400BadRequest; return(new BadRequestObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); }; }
internal static IActionResult ProblemDetailsInvalidModelStateResponse( ProblemDetailsFactory problemDetailsFactory, ActionContext context) { var problemDetails = problemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState); var result = (HttpStatusCode?)problemDetails.Status == HttpStatusCode.BadRequest ? new BadRequestObjectResult(problemDetails) : new ObjectResult(problemDetails); result.ContentTypes.Add("application/problem+json"); result.ContentTypes.Add("application/problem+xml"); return(result); }
private ProblemDetails BuildProblemDetails <TEx>(TEx ex, int status, HttpContext context) where TEx : Exception { if (ex is ValidationException valEx) { var state = new ModelStateDictionary(); foreach (var err in valEx.Errors) { state.AddModelError(err.Context, err.Message); } return(_problemDetailsFactory.CreateValidationProblemDetails(context, state, status, ex.Message, null, null, context.Request.Path)); } return(_problemDetailsFactory.CreateProblemDetails(context, status, ex.Message, null, null, context.Request.Path)); }
private static ValidationProblemDetails HandleValidationProblemDetails(ValidationExceptionBase ex) { _context.Response.StatusCode = (int)ex.StatusCode; var modelStateDictionary = new ModelStateDictionary(); modelStateDictionary.AddModelError(ex.Property, ex.Message); var problemDetails = _problemDetailsFactory.CreateValidationProblemDetails( _context, statusCode: (int)ex.StatusCode, detail: _includeStackTrace ? ex.ToString() : ex.Message, modelStateDictionary: modelStateDictionary ); return(problemDetails); }
public void ConfigureServices(IServiceCollection services) { RegisterServices(services); RegisterDateTimeProvider(services); ConfigureDatabase(services); ConfigureCors(services); services.AddMediatR(typeof(Login.Handler).Assembly); services.AddGenericMediatorHandlers(); services.AddAutoMapper( typeof(LoginDtoMappingProfile).Assembly, typeof(Modify.MappingProfile).Assembly); services.AddHealthChecks().AddDbContextCheck <ArpaContext>(); services.Configure <ApiBehaviorOptions>(options => options.SuppressInferBindingSourcesForParameters = true); services .AddControllers() .AddJsonOptions(options => options.JsonSerializerOptions.Converters .Add(new DateTimeJsonConverter())) .AddApplicationPart(typeof(Startup).Assembly) .AddFluentValidation(config => { config.RegisterValidatorsFromAssemblyContaining <LoginDtoValidator>(); config.RegisterValidatorsFromAssemblyContaining <Validator>(); config.ValidatorFactoryType = typeof(HttpContextServiceProviderValidatorFactory); // Workaround https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation#error-systeminvalidoperationexception-cannot-resolve-ivalidatort-from-root-provider-because-it-requires-scoped-service-tdependency }) .ConfigureApiBehaviorOptions(options => { options.InvalidModelStateResponseFactory = context => { ProblemDetailsFactory problemDetailsFactory = context.HttpContext.RequestServices.GetRequiredService <ProblemDetailsFactory>(); ValidationProblemDetails problemDetails = problemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState, statusCode: 422); var result = new UnprocessableEntityObjectResult(problemDetails); result.ContentTypes.Add("application/problem+json"); result.ContentTypes.Add("application/problem+xml"); return(result); }; }); ConfigureSwagger(services); ConfigureAuthentication(services); ConfigureAuthorization(services); }
public IActionResult Authentication(SimDeviceAuthenticationRequest simDeviceAuthenticationRequest) { var simMsisdn = simDeviceAuthenticationRequest.SimMsisdn; var simImsi = simDeviceAuthenticationRequest.SimImsi; var simIccId = simDeviceAuthenticationRequest.SimIccId; var certBase64String = simDeviceAuthenticationRequest.ClientCertificationBase64; var subjectCn = CertificateUtil.GetSubjectCommonNameByCertificationBase64(certBase64String); if (subjectCn == null) { var validationProblemDetails = ProblemDetailsFactory.CreateValidationProblemDetails(HttpContext, ModelState); validationProblemDetails.Errors.Add(new KeyValuePair <string, string[]>("ClientCertificationBase64", new[] { "certification_invalid" })); return(BadRequest(validationProblemDetails)); } var simDevice = _authenticationRepository.GetSimDevice(simMsisdn, simImsi, simIccId, subjectCn); if (simDevice == null) { Sim sim = _authenticationRepository.GetSim(simMsisdn, simImsi, simIccId); if (sim == null) { _logger.LogWarning($"Not Found SIM:{simMsisdn}"); } else { CreateSimAndDeviceAuthenticationFailureLog(sim); _radiusDbRepository.UpdateRadreply(sim.UserName + "@" + sim.SimGroup.UserNameSuffix); } return(Unauthorized(NotMatchSimDevice)); } // 認証成功のSimDeviceによって それに対応する LoginできるUser を検索します var canLogonUsers = _authenticationRepository.GetLoginUsers(subjectCn); _radiusDbRepository.UpdateRadreply(simDevice.Sim.UserName + "@" + simDevice.Sim.SimGroup.UserNameSuffix, simDevice.IsolatedNw2Ip); CreateSimAndDeviceAuthenticationSuccessLog(simDevice); // SimDeviceによって 認証状態を検索する すでに登録したら SimAndDeviceAuthenticated を更新します var simDeviceAuthenticationStateDone = CreateSimAndDeviceAuthenticated(simDevice); var simDeviceAuthenticationResponse = CreateSimDeviceAuthenticationResponse(simDeviceAuthenticationStateDone, simDevice, canLogonUsers); return(Ok(simDeviceAuthenticationResponse)); }
/// <summary> /// Creates a <see cref="ValidationProblemDetails" /> instance that configures defaults based on values specified in <see cref="ApiBehaviorOptions" />. /// </summary> /// <param name="httpContext">The <see cref="HttpContext" />.</param> /// <param name="modelStateDictionary">The <see cref="ModelStateDictionary" />.</param> /// <param name="statusCode">The value for <see cref="ProblemDetails.Status" />.</param> /// <param name="title">The value for <see cref="ProblemDetails.Title" />.</param> /// <param name="type">The value for <see cref="ProblemDetails.Type" />.</param> /// <param name="detail">The value for <see cref="ProblemDetails.Detail" />.</param> /// <param name="instance">The value for <see cref="ProblemDetails.Instance" />.</param> /// <returns>The <see cref="ValidationProblemDetails" /> instance.</returns> public override ValidationProblemDetails CreateValidationProblemDetails( HttpContext httpContext, ModelStateDictionary modelStateDictionary, int?statusCode = null, string title = null, string type = null, string detail = null, string instance = null) { return(ReplaceTraceId(_inner.CreateValidationProblemDetails(httpContext, modelStateDictionary, statusCode, title, type, detail, instance ))); }
// creates validation problem details instance. // borrowed from netcore: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ControllerBase.cs#L1970 protected ValidationProblemDetails?GetValidationProblemDetails( string?detail = null, string?instance = null, int?statusCode = null, string?title = null, string?type = null, [ActionResultObjectValue] ModelStateDictionary?modelStateDictionary = null) { modelStateDictionary ??= ModelState; ValidationProblemDetails?validationProblem; if (ProblemDetailsFactory == null) { // ProblemDetailsFactory may be null in unit testing scenarios. Improvise to make this more testable. validationProblem = new ValidationProblemDetails(modelStateDictionary) { Detail = detail, Instance = instance, Status = statusCode, Title = title, Type = type, }; } else { validationProblem = ProblemDetailsFactory?.CreateValidationProblemDetails( HttpContext, modelStateDictionary, statusCode: statusCode, title: title, type: type, detail: detail, instance: instance); } return(validationProblem); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(setup => { setup.ReturnHttpNotAcceptable = true; } ).AddXmlDataContractSerializerFormatters() .AddFluentValidation(configuration => configuration.RegisterValidatorsFromAssemblyContaining <Startup>()) .ConfigureApiBehaviorOptions(setupAction => { setupAction.InvalidModelStateResponseFactory = context => { ProblemDetailsFactory problemDetailsFactory = context.HttpContext.RequestServices .GetRequiredService <ProblemDetailsFactory>(); ValidationProblemDetails problemDetails = problemDetailsFactory.CreateValidationProblemDetails( context.HttpContext, context.ModelState); problemDetails.Detail = "Check error field for details"; problemDetails.Instance = context.HttpContext.Request.Path; var actionExecutiongContext = context as ActionExecutingContext; if ((context.ModelState.ErrorCount > 0) && (actionExecutiongContext?.ActionArguments.Count == context.ActionDescriptor.Parameters.Count)) { problemDetails.Type = "https://google.com"; problemDetails.Status = StatusCodes.Status422UnprocessableEntity; problemDetails.Title = "Failed to validate"; return(new UnprocessableEntityObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); } problemDetails.Status = StatusCodes.Status400BadRequest; problemDetails.Title = "Failed to parse the content"; return(new BadRequestObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); }; }); services.AddDbContext <UserDbContext>(); services.AddDbContext <IdentityUserDbContext>(); services.AddIdentity <AccountInfo, AccountRole>(options => { options.Password.RequireDigit = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequiredLength = 6; options.Password.RequireLowercase = false; options.Password.RequireUppercase = false; }).AddEntityFrameworkStores <IdentityUserDbContext>(); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddSingleton <ILogger, Logger>(); services.AddSingleton <ILoggerProvider, LoggerProvider>(); services.AddScoped <IPersonalUserRepository, PersonalUserRepository>(); services.AddScoped <ICorporationUserRepository, CorporationUserRepository>(); services.AddScoped <ICountryRepository, CountryRepository>(); services.AddScoped <IRoleRepository, RoleRepository>(); services.AddScoped <IPersonalUsersService, PersonalUsersService>(); services.AddScoped <ICountryService, CountryService>(); services.AddScoped <IRolesService, RolesService>(); services.AddScoped <ICorporationUsersService, CorporationUsersService>(); services.AddSwaggerGen(setupAction => { setupAction.SwaggerDoc("UserServiceOpenApiSpecification", new Microsoft.OpenApi.Models.OpenApiInfo() { Title = "User Service API", Version = "1", Description = "API for creating, updating and fetcing users, roles and countries", Contact = new Microsoft.OpenApi.Models.OpenApiContact { Name = "Djordje Stefanovic", Email = "*****@*****.**", } }); }); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddResponseCaching(); services.AddControllers(setupAction => { setupAction.ReturnHttpNotAcceptable = true; setupAction.CacheProfiles.Add("240SecondsCacheProfile", new CacheProfile() { Duration = 240 }); }).AddNewtonsoftJson() .AddXmlDataContractSerializerFormatters() .ConfigureApiBehaviorOptions(options => { options.InvalidModelStateResponseFactory = context => { ProblemDetailsFactory problemDetailsFactory = context.HttpContext.RequestServices .GetRequiredService <ProblemDetailsFactory>(); var problemDetails = problemDetailsFactory.CreateValidationProblemDetails( context.HttpContext, context.ModelState); problemDetails.Instance = context.HttpContext.Request.Path; var actionExecutingContext = context as ActionExecutingContext; if ((context.ModelState.ErrorCount > 0) && (actionExecutingContext?.ActionArguments.Count == context.ActionDescriptor.Parameters.Count)) { problemDetails.Status = StatusCodes.Status422UnprocessableEntity; problemDetails.Title = "One or more validation errors occurred."; return(new UnprocessableEntityObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); } problemDetails.Status = StatusCodes.Status400BadRequest; problemDetails.Title = "One or more errors on input occurred."; return(new BadRequestObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); }; }); services.Configure <MvcOptions>(config => { var jsonFormatter = (NewtonsoftJsonOutputFormatter)(config.OutputFormatters.FirstOrDefault(of => of.GetType() == typeof(NewtonsoftJsonOutputFormatter))); if (jsonFormatter != null) { jsonFormatter.SupportedMediaTypes.Add("application/vnd.marvin.hateoas+json"); } }); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddMemoryCache(); services.AddSingleton <IAsyncCacheProvider, MemoryCacheProvider>(); IPolicyRegistry <string> registry = services.AddPolicyRegistry(); services.AddHttpClient <IAuthenticationClientAsync, AuthenticationClientAsync>().ConfigurePrimaryHttpMessageHandler(h => { var handler = new HttpClientHandler(); var certificateFilepath = Configuration["BetfairApi:Authentication:CertificateFilepath"]; var cert = new X509Certificate2(certificateFilepath, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); handler.ClientCertificates.Add(cert); return(handler); }); services.Configure <DataProviderMappings>((settings) => { Configuration.GetSection("DataProviders").Bind(settings); }); services.AddHttpClient <IRequestInvokerAsync, RequestInvokerAsync>(); string connectionString = Configuration["ConnectionStrings:BetfairMetadataServiceDb"]; services.AddDbContext <BetfairMetadataServiceContext>(o => o.UseSqlServer(connectionString)); services.AddScoped <IBatchReader <DataProvider>, ConfigurationBatchDataProviderReader>(); services.AddScoped <IReader <DataProvider, int>, ConfigurationDataProviderReader>(); services.AddScoped <IReader <EventType, string>, BetfairEventTypeReader>(); services.AddScoped <IReader <Competition, string>, BetfairCompetitionReader>(); services.AddScoped <IBetfairBatchReader <EventType>, BetfairEventTypesBatchReader>(); services.AddScoped <IBetfairBatchReader <Competition>, BetfairCompetitionsBatchReader>(); services.AddScoped <IBetfairBatchReader <Event>, BetfairEventsBatchReader>(); services.AddScoped <IBetfairBatchReader <MarketType>, BetfairMarketTypesBatchReader>(); services.AddScoped <IBetfairBatchReader <Market>, BetfairMarketsBatchReader>(); services.AddScoped <Func <int, IExternalEventTypesRepository> >(sp => dataProviderId => { switch (dataProviderId) { case (1): return(new BetfairEventTypesRepository(sp.GetRequiredService <IBetfairBatchReader <EventType> >())); default: return(null); } }); services.AddScoped <Func <int, IExternalCompetitionsRepository> >(sp => dataProviderId => { switch (dataProviderId) { case (1): return(new BetfairCompetitionsRepository(sp.GetRequiredService <IBetfairBatchReader <Competition> >())); default: return(null); } }); services.AddScoped <Func <int, IExternalEventsRepository> >(sp => dataProviderId => { switch (dataProviderId) { case (1): return(new BetfairEventsRepository(sp.GetRequiredService <IBetfairBatchReader <Event> >())); default: return(null); } }); services.AddScoped <Func <int, IExternalMarketTypesRepository> >(sp => dataProviderId => { switch (dataProviderId) { case (1): return(new BetfairMarketTypesRepository(sp.GetRequiredService <IBetfairBatchReader <MarketType> >())); default: return(null); } }); services.AddScoped <Func <int, IExternalMarketsRepository> >(sp => dataProviderId => { switch (dataProviderId) { case (1): return(new BetfairMarketsRepository(sp.GetRequiredService <IBetfairBatchReader <Market> >())); default: return(null); } }); services.AddScoped <IDeleter <EventTypeMarketType>, EventTypeMarketTypeFetchRootDeleter>(); services.AddScoped <ISaver <EventTypeMarketType>, EventTypeMarketTypeFetchRootSaver>(); services.AddScoped <IReader <EventTypeMarketType, Tuple <int, string, string> >, EventTypeMarketTypeFetchRootReader>(); services.AddScoped <IDeleter <CompetitionMarketType>, CompetitionMarketTypeFetchRootDeleter>(); services.AddScoped <ISaver <CompetitionMarketType>, CompetitionMarketTypeFetchRootSaver>(); services.AddScoped <IReader <CompetitionMarketType, Tuple <int, string, string> >, CompetitionMarketTypeFetchRootReader>(); services.AddScoped <IEntityUpserter, EntityUpserter>(); services.AddScoped(typeof(IBatchReader <>), typeof(BatchReader <>)); services.AddScoped <IReader <Domain.Internal.EventType, string>, Reader <Domain.Internal.EventType> >(); services.AddScoped <IReader <Domain.Internal.Competition, string>, Reader <Domain.Internal.Competition> >(); services.AddScoped <IReader <Domain.Internal.Event, string>, Reader <Domain.Internal.Event> >(); services.AddScoped <IReader <Domain.Internal.Market, string>, Reader <Domain.Internal.Market> >(); services.AddScoped <IReader <Domain.Internal.Selection, string>, Reader <Domain.Internal.Selection> >(); services.AddScoped <BetfairCompetitionsWorker>(); services.AddScoped <IWorker>(sp => new CompositeWorker( new IWorker[] { sp.GetRequiredService <BetfairCompetitionsWorker>() })); services.AddScoped <ICompetitionMarketTypeWorker, BetfairCompetitionWorker>(); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(setup => { //Content negotiation in Accept header of users request setup.Filters.Add <ValidationFilter>(); setup.ReturnHttpNotAcceptable = true; } ).AddXmlDataContractSerializerFormatters() .AddFluentValidation(configuration => configuration.RegisterValidatorsFromAssemblyContaining <Startup>()) .ConfigureApiBehaviorOptions(setupAction => //Deo koji se odnosi na podržavanje Problem Details for HTTP APIs { setupAction.InvalidModelStateResponseFactory = context => { //Kreiramo problem details objekat ProblemDetailsFactory problemDetailsFactory = context.HttpContext.RequestServices .GetRequiredService <ProblemDetailsFactory>(); //Prosleđujemo trenutni kontekst i ModelState, ovo prevodi validacione greške iz ModelState-a u RFC format ValidationProblemDetails problemDetails = problemDetailsFactory.CreateValidationProblemDetails( context.HttpContext, context.ModelState); //Ubacujemo dodatne podatke problemDetails.Detail = "Check error field for details"; problemDetails.Instance = context.HttpContext.Request.Path; //po defaultu se sve vraća kao status 400 BadRequest, to je ok kada nisu u pitanju validacione greške, //ako jesu hoćemo da koristimo status 422 UnprocessibleEntity //tražimo info koji status kod da koristimo var actionExecutiongContext = context as ActionExecutingContext; //proveravamo da li postoji neka greška u ModelState-u, a takođe proveravamo da li su svi prosleđeni parametri dobro parsirani //ako je sve ok parsirano ali postoje greške u validaciji hoćemo da vratimo status 422 if ((context.ModelState.ErrorCount > 0) && (actionExecutiongContext?.ActionArguments.Count == context.ActionDescriptor.Parameters.Count)) { problemDetails.Type = "https://google.com"; //inače treba da stoji link ka stranici sa detaljima greške problemDetails.Status = StatusCodes.Status422UnprocessableEntity; problemDetails.Title = "Failed to validate"; //sve vraćamo kao UnprocessibleEntity objekat return(new UnprocessableEntityObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); } //ukoliko postoji nešto što nije moglo da se parsira hoćemo da vraćamo status 400 kao i do sada problemDetails.Status = StatusCodes.Status400BadRequest; problemDetails.Title = "Failed to parse the content"; return(new BadRequestObjectResult(problemDetails) { ContentTypes = { "application/problem+json" } }); }; }); services.AddDbContext <UserDbContext>(); services.AddDbContext <IdentityUserDbContext>(); //Adding Identity services.AddIdentity <AccountInfo, AccountRole>(options => { options.Password.RequireDigit = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequiredLength = 6; options.Password.RequireLowercase = false; options.Password.RequireUppercase = false; }).AddEntityFrameworkStores <IdentityUserDbContext>(); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddScoped <IPersonalUserRepository, PersonalUserRepository>(); services.AddScoped <ICorporationUserRepository, CorporationUserRepository>(); services.AddScoped <ICityRepository, CityRepository>(); services.AddScoped <IRoleRepository, RoleRepository>(); services.AddScoped <IPersonalUsersService, PersonalUsersService>(); services.AddScoped <ICitiesService, CitiesService>(); services.AddScoped <IRolesService, RolesService>(); services.AddScoped <ICorporationUsersService, CorporationUsersService>(); services.AddScoped <ResourceOwnerFilter>(); var jwtSettings = new JwtSettings(); Configuration.Bind(nameof(jwtSettings), jwtSettings); services.AddSingleton(jwtSettings); services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.Secret)), ValidateIssuer = false, ValidateAudience = false, RequireExpirationTime = false, ValidateLifetime = true }; }); services.AddSwaggerGen(setupAction => { setupAction.SwaggerDoc("UserServiceOpenApiSpecification", new Microsoft.OpenApi.Models.OpenApiInfo() { Title = "User Service API", Version = "1", Description = "API for creating, updating and fetcing users, roles and cities", Contact = new Microsoft.OpenApi.Models.OpenApiContact { Name = "Natalija Gajić", Email = "*****@*****.**", }, License = new Microsoft.OpenApi.Models.OpenApiLicense { Name = "FTN licence" } }); setupAction.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, Scheme = "Bearer" }); setupAction.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Scheme = "oauth2", Name = "Bearer", In = ParameterLocation.Header, }, new List <string>() } }); }); }