Base solution for your next web application
Open Closed

Web API / app service with CORS. Unexpected validation error after ajax call #11091


User avatar
0
lalande1988 created

Prerequisites

  • What is your product version? ASP.NET Zero 11.0
  • What is your product type (Angular or MVC)? MVC
  • What is product framework type (.net framework or .net core)? .NET Core

Task

Implement a Web API post utilizing CORS. To start with: all origins allowed and without authentication.

Thank you for your support!

Overview

Two app service function exist. Both HttpPost, one expects input, the other is a call without any parameter. Swagger & Postman work fine with both. A demo client making a cross-origin call works with the parameter-less function. The function expecting a parameter creates a validation error. The validation error is not due to violating a rule of the input class. I tested existing APIs, like roles/getroles after having disabled authentication. The same class of error, validation before it comes to input validation.

Details

Excerpt from Logs.txt, this might be most helpful? Unfortunately, not for me... See at the end of the message, maybe easier to copy / paste ro review.

Client code and response

Ajax call in the client:

$.ajax({
    contentType: 'application/json',
    data: formData.premiumInput,
    type: 'post',
    url: serviceUrl.href,
})
    .done(function (data, textStatus, jqXHR) {
        ....
    })

    .fail(function (jqXHR, textStatus, errorThrown) {
        ...
    });

Notes: data and url are checked, they do not cause trouble. crossDomain: true makes no difference.

Response (in failed()):

responseJSON:
error:
code: 0
details: "Die folgenden Fehler wurden während der Validierung entdeckt.\r\n - Error parsing boolean value. Path '', line 1, position 1.\r\n"
message: "Die Anfrage war ungültig!"
validationErrors: Array(1)
0:
members: ['']
message: "Error parsing boolean value. Path '', line 1, position 1."
result: null
success: false
targetUrl: null
unAuthorizedRequest: false
__abp: true

The German details / message means: error during validation. The Error parsing boolean value is not clear. For the records:

formData.premiumInput = {
    "territory": 1,
    "postcode": "B37 7HQ",
    "eircode": "",
    "address_1": "",
    "address_2": "",
    "occupancy": 0,
    "buildingType": 0,
    "yearBuilt": 2000,
    "sumInsuredBuilding": 100000,
    "sumInsuredContents": 200000,
    "sumInsuredBi": 300000,
    "deductibleFlood": 250,
    "deductibleFreeze": 250,
    "deductibleStormSurge": 250,
    "deductibleSubsidence": 250,
    "deductibleTheft": 250,
    "deductibleWindstorm": 250,
    "percentageRiskShare": 80
};

App Service

namespace PerilManager.Premiums
{
    //    [AbpAuthorize]
    [EnableCors("CorsPolicy")]
    public class PremiumAppService : PerilManagerAppServiceBase, IPremiumAppService
    {
        [HttpPost]
        public async Task<CalcPremiumsOutput> GetCalcPremiums(CalcPremiumsInput input)
        {
            double flood = 3 * input.DeductibleFlood;
            CalcPremiumsOutput output = await Task.FromResult(new CalcPremiumsOutput()
            {
                Flood = flood,
                StormSurge = 3939.00,
                Windstorm = 3939.39,
                Freeze = 303.49,
                Subsidence = 1.38383,
                Theft = 300
            });

            return output;
        }

        [HttpPost]
        public async Task<CalcPremiumsOutput> UpdatePremiums()
        {
            CalcPremiumsOutput output = await Task.FromResult(new CalcPremiumsOutput()
            {
                Flood = 299,
                StormSurge = 3939.00,
                Windstorm = 3939.39,
                Freeze = 303.49,
                Subsidence = 1.38383,
                Theft = 300
            });

            return output;
        }
    }
}

Logs.txt

INFO 2022-06-01 13:33:53,669 [orker] Microsoft.AspNetCore.Hosting.Diagnostics - Request starting HTTP/2 OPTIONS https://localhost:44302/api/services/app/premium/getcalcpremiums - - INFO 2022-06-01 13:33:53,669 [orker] pNetCore.Cors.Infrastructure.CorsService - CORS policy execution successful. INFO 2022-06-01 13:33:53,670 [orker] Microsoft.AspNetCore.Hosting.Diagnostics - Request finished HTTP/2 OPTIONS https://localhost:44302/api/services/app/premium/getcalcpremiums - - - 204 - - 1.0952ms INFO 2022-06-01 13:33:53,681 [orker] Microsoft.AspNetCore.Hosting.Diagnostics - Request starting HTTP/2 POST https://localhost:44302/api/services/app/premium/getcalcpremiums application/json 333 INFO 2022-06-01 13:33:53,682 [orker] pNetCore.Cors.Infrastructure.CorsService - CORS policy execution successful. INFO 2022-06-01 13:33:53,683 [orker] pNetCore.Cors.Infrastructure.CorsService - CORS policy execution successful. INFO 2022-06-01 13:33:53,683 [orker] ft.AspNetCore.Routing.EndpointMiddleware - Executing endpoint 'PerilManager.Premiums.PremiumAppService.GetCalcPremiums (PerilManager.Application)' INFO 2022-06-01 13:33:53,685 [orker] c.Infrastructure.ControllerActionInvoker - Route matched with {area = "app", action = "GetCalcPremiums", controller = "Premium"}. Executing controller action with signature System.Threading.Tasks.Task`1[PerilManager.Premiums.Dto.CalcPremiumsOutput] GetCalcPremiums(PerilManager.Premiums.Dto.CalcPremiumsInput) on controller PerilManager.Premiums.PremiumAppService (PerilManager.Application). INFO 2022-06-01 13:33:53,692 [orker] osoft.EntityFrameworkCore.Infrastructure - Entity Framework Core 6.0.0 initialized 'PerilManagerDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.0' with options: None WARN 2022-06-01 13:33:53,705 [orker] Mvc.ExceptionHandling.AbpExceptionFilter - Method arguments are not valid! See ValidationErrors for details. Abp.Runtime.Validation.AbpValidationException: Method arguments are not valid! See ValidationErrors for details. at Abp.Runtime.Validation.Interception.MethodInvocationValidator.ThrowValidationError() at Abp.Runtime.Validation.Interception.MethodInvocationValidator.Validate() at Abp.AspNetCore.Mvc.Validation.AbpValidationActionFilter.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.


4 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Could you try calling your service as shown below ?

    abp.services.app.premium.getCalcPremiums(formData.premiumInput)
    
  • User Avatar
    0
    lalande1988 created

    Thank you for you r feedback!

    Your suggestion works fine, as expected. Find the code and console response below.

    To avoid misunderstandings: the Web API will be utilized by a customer, i.e. from any web page making an ajax call. They could even use a different technology. My test setup is a web page making the call as in the example at the top.

    So: making the call from a view on my page works fine, so does Swagger and Postman. Only another page making a cross origin call fails.

    js Code:

        console.log("starting premium test");
        let formData = {
            "premiumInput": {
                "territory": 1,
                "postcode": "B37 7HQ",
                "eircode": "",
                "address_1": "",
                "address_2": "",
                "occupancy": 0,
                "buildingType": 0,
                "yearBuilt": 2000,
                "sumInsuredBuilding": 100000,
                "sumInsuredContents": 200000,
                "sumInsuredBi": 300000,
                "deductibleFlood": 111,   // only this will be evaluated to know we have reached the service
                "deductibleFreeze": 250,
                "deductibleStormSurge": 250,
                "deductibleSubsidence": 250,
                "deductibleTheft": 250,
                "deductibleWindstorm": 250,
                "percentageRiskShare": 80
            }
        };
        let premiumService = abp.services.app.premium;
        premiumService
            .getCalcPremiums(formData.premiumInput)
            .done(function (result) {
                console.log("done premium test", JSON.stringify(result));
            })
            .fail(function (result) {
                console.log("failes premium test", JSON.stringify(result));
            });
    
    

    The only dummy calculation is flood = 3 * deductibleFlood (3 * 111 = 333). The other values are constant.

    Thank you and kind regards!

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    I got it now, thanks for the explanation. In that case, you need to allow the websites which will make a request or all websites by enabling CORS, see https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-6.0

  • User Avatar
    0
    lalande1988 created

    Hi,

    Thank you!

    CORS has been enabled in the startup.cs file. If this is not the case, the error will be different. I.e. in that case the error will be in the chrome developer console correctly stating that CORS has not been enabled. Without CORS the case of the empty (call without ajax data) would not be working as well.

    It looks like there is a kind of pre-validation before the validation of my data.

    Maybe you have one more idea?

    Thank you and kind regards!

    Startup:

        services.AddCors(options =>
        {
            options.AddPolicy(name: _corsPolicy, policy =>
            {
                policy
                .AllowAnyOrigin()
                .AllowAnyHeader()
                .AllowAnyMethod()
                ;
            });
        });
        .....
        app.UseCors(_corsPolicy);  // Note: must be after UseRouting and before UseAuthorization