简体   繁体   中英

Handle both GET and POST request with same route in .net core controller

I am trying to handle both the GET and the POST in the same controller with the same route, as I have certain rest calls that the data may use a GET or a POST to call the same endpoint....

This works fine with a GET:

[Produces("application/json")]
[ApiController]
public class AccountController : ControllerBase
{
    [HttpGet("GetAccount")]
    [Route("api/accounts/GetAccount")]
    public string GetAccount(string accountID)
    {
        return "echoing accountID: " + accountID;
    }
}

And this works for POST:

[Produces("application/json")]
[ApiController]
public class AccountController : ControllerBase
{
    [HttpPost("GetAccount")]
    [Route("api/accounts/GetAccount")]
    public string GetAccount([FromForm] string accountID)
    {
        return "echoing accountID: " + accountID;
    }
}

But this does not return the values from a POST:

[Produces("application/json")]
[ApiController]
public class AccountController : ControllerBase
{
    [HttpPost("GetAccount"),HttpGet("GetAccount")]
    [Route("api/accounts/GetAccount")]
    public string GetAccount(string accountID)
    {
        // accountID is NULL when doing a POST, but is correct for a GET...
        return "echoing accountID: " + accountID;
    }
}

In the above example, a GET request works fine, but when doing a POST, the parameter accountID is NULL, because I have removed the [FromForm] in order to make it work with a GET.

Is there some way that I can combine this into a single route?

This is for a .net core 5.0 site....

Example of how I am posting to the endpoint from javascript:

$.ajax({
   url: '/api/accounts/GetAccount',
   data: {
      accountID: 'abcdefg'
   },
   type: 'POST',
   dataType: 'JSON',
   contentType: "application/x-www-form-urlencoded; charset=UTF-8" 
})
   .done(function (result) {
      // verified that the result is NULL
      console.log(result);
   })
   .fail(function () {
      alert("ERROR");;
   })
   .always(function () {
      alert("DONE");
   });

And here is my complete Startup file (in case I don't have something registered correctly):

public class Startup
{
   public Startup(IConfiguration configuration)
   {
      Configuration = configuration;
   }

   public IConfiguration Configuration { get; }

   public void ConfigureServices(IServiceCollection services)
   {
      services.AddSession();
      services.AddHttpContextAccessor();
      services.AddRazorPages();
      services.AddControllers();
      services.AddControllers().AddNewtonsoftJson();
      services.AddControllersWithViews();
   }

   public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
   {
      app.UseSession();
      app.UseExceptionHandler("/Error");
      app.UseHsts();
      app.UseHttpsRedirection();
      app.UseStaticFiles();
      app.UseRouting();
      app.UseAuthentication();
      app.UseAuthorization();

      app.UseEndpoints(endpoints =>
      {
         endpoints.MapRazorPages();
         endpoints.MapControllers();
      });
    }
}

Thanks!

You can try to change your code like below:

    [HttpPost("GetAccount"), HttpGet("GetAccount")]
    [Route("api/accounts/GetAccount")]
    public string GetAccount()        
    {
        if ("GET" == HttpContext.Request.Method)
        {
            //if your `accountID` is fromquery in your get method.
            string accountID = HttpContext.Request.Query["accountID"];
            return "echoing accountID: " + accountID;
        }

        else if ("POST" == HttpContext.Request.Method)
        {
            string accountID = HttpContext.Request.Form["accountID"];
            return "echoing accountID: " + accountID;
        }
        else
        {
            return "error";
        }
    }

In addition, I think there may be no problem with your code. When issuing the post method, you should check your accountID parameter.

Update

The default attribute of the api controller is [FromBody], so you must specify the source.If you don't want to specify as [FromForm], you can pass data through querystring.

$.ajax({
            url: '/api/values/GetAccount?accountID=abcdefg',
            type: 'POST',
            dataType: 'JSON',
            contentType: "application/x-www-form-urlencoded; charset=UTF-8"
        })
            .done(function (result) {
                // verified that the result is NULL
                console.log(result.message);
            })
            .fail(function () {
                alert("ERROR");;
            })
            .always(function () {
                alert("DONE");
            });
    });

Action:

    [HttpPost("GetAccount"), HttpGet("GetAccount")]
    [Route("api/accounts/GetAccount")]
    public IActionResult GetAccount(string accountID)
    {
        string message = "echoing accountID: " + accountID;
        // accountID is NULL when doing a POST, but is correct for a GET...
        return new JsonResult(new { message = message });
    }

Have you tried to create two separate functions. One for GET and the other for POST? You can still set the Route attribute the same but it will be the HTTP method which from the consumer which will determine which method will be invoked.

Also, you need to use the [FromBody] attribute to access any payload that is sent with the request.

[Produces("application/json")]
[ApiController]
public class AccountController : ControllerBase
{
    [HttpGet]
    [Route("api/accounts/GetAccount")]
    public string GetAccount([FromBody] request)
    {
        return "echoing accountID: " + request.accountID;
    }

    [HttpPost]
    [Route("api/accounts/GetAccount")]
    public string CreateAccount([FromBody] request)
    {
        return "echoing accountID: " + request.accountID;
    }
}

EDIT

You may need to use [FromQuery] for your GET endpoint and [FromBody] for your POST endpoint.

Then for your GET, your URL will use query parameters instead of a data payload. eg /api/accounts/GetAccount?accountID=12345

[Produces("application/json")]
[ApiController]
public class AccountController : ControllerBase
{
    [HttpGet]
    [Route("api/accounts/GetAccount")]
    public string GetAccount([FromQuery] request)
    {
        return "echoing accountID: " + request.accountID;
    }

    [HttpPost]
    [Route("api/accounts/GetAccount")]
    public string CreateAccount([FromBody] request)
    {
        return "echoing accountID: " + request.accountID;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM