For example:
api/file/occurrence?sha256=...
[HttpGet]
[Route("api/file/")]
public async Task<IHttpActionResult> GetFileBySha256Async([FromUri] FilesBySha256RequestDTO requestDTO)
{
}
api/file/occurrence?sha256=...&from_date=..&to_date=..
[HttpGet]
[Route("api/file/")]
public async Task<IHttpActionResult> GetFileBySha256AndDateAsync([FromUri] FilesBySha256AndDateRequestDTO requestDTO)
{
}
And the DTOs:
public class FilesBySha256RequestDTO
{
public string sha256 { get; set; }
}
public class FilesBySha256AndDateRequestDTO
{
public string sha256 { get; set; }
public DateTime? from_date { get; set; }
public DateTime? to_date { get; set; }
}
How can I accomplish this behavior? I am getting the following exception:
"ExceptionMessage": "Multiple actions were found that match the request: \r\nGetFileBySha256Async on type Cynet.Client.WebAPI.Controllers.FileController\r\nGetFileOccurrencesSha256 on type Cynet.Client.WebAPI.Controllers.FileController
It is not possible to distinguish the route between two because api/file/occurrence?sha256=...&from_date=..&to_date=.. and api/file/occurrence?sha256=... is the same thing for the framework. The first thing you can do is changing the second route like api/fileOnDate/. If it is impossible to do it, you can define a third function and use it as a manual router such as;
[HttpGet]
[Route("api/file/")]
public async Task<IHttpActionResult> GetFileBy([FromUri] FilesBySha256AndDateRequestDTO requestDTO)
{
if (!requestDTO.from_date.HasValue && !requestDTO.to_date.HasValue)
{
return await this.GetFileBySha256Async(new FilesBySha256RequestDTO() { sha256 = requestDTO.sha256 });
}
else
{
return await this.GetFileBySha256AndDateAsync(requestDTO);
}
}
private async Task<IHttpActionResult> GetFileBySha256Async(FilesBySha256RequestDTO requestDTO)
{
}
private async Task<IHttpActionResult> GetFileBySha256AndDateAsync(FilesBySha256AndDateRequestDTO requestDTO)
{
}
hope it helps.
Related
Is it possible to overload an api endpoint by object type in C#? Here is my attempt to overload CreateDocument endpoint with document types Contract1 and Contract2,
[HttpPost("CreateDocument")]
public async Task<object> CreateDocument(CustomerDocument<Contract1> document)
{
return CreateDocument<Contract1>(document);
}
[HttpPost("CreateDocument")]
public async Task<object> CreateDocument(CustomerDocument<Contract2> document)
{
return CreateDocument<Contract2>(document);
}
private async Task<object> CreateDocument<T>(CustomerDocument<T> document)
{
//do stuff
}
My Model
public class CustomerDocument
{
public string Id { get; set; }
public string AccountId { get; set; }
public T DocData { get; set; }
public CustomerDocument(T initialValue)
{
DocData = initialValue;
}
}
I get the error
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The
request matched multiple endpoints.
I would love to know a shorter solution that would not use the dynamic object, but this allows using multiple object types in one api method by using an id and a switch statement.
[HttpPost("CreateDocument")]
public async Task<object> CreateDocument(dynamic document, int id)
{
switch (id) {
case 0:
return await CreateDocument<Contract1>(JsonConvert.DeserializeObject<CustomerDocument<Contract1>>(document));
case 1:
return await CreateDocument<Contract2>(JsonConvert.DeserializeObject<CustomerDocument<Contract2>>(document));
//other cases ...
default:
return Json("Error");
}
}
private async Task<object> CreateDocument<T>(CustomerDocument<T> document)
{
//do stuff
}
I'm writing a mobile app using Xamarin Forms where I am going to consume an REST API.
At the moment, I have a user model
{
public string UserId { get; set; }
public string UserDisplayName { get; set; }
public int UserRoleId { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserEmail { get; set; }
public string UserPostcode { get; set; }
public DateTime UserCreatedAt { get; set; }
public DateTime UserModifiedAt { get; set; }
public bool UserDeletedAt { get; set; }
}
And I have defined a GetUser method on my controller
// GET: api/Users/5
[HttpGet("{id}")]
public async Task<ActionResult<User>> GetUser(string id)
{
var user = await _context.User.FindAsync(id);
if (user == null)
{
return NotFound();
}
return user;
}
If I test the API using Postman and parse the string id without quotes(edit) on the route, it works fine. E.g. https://localhost:5051/api/Users/Example. However, if I parse the id within qutoes(edit) it doesn't work: https://localhost:5051/api/Users/"Example"
My problem is, on my mobile client, when it calls the web service that calls the API, it needs to parse a string, which goes with the quotes(edit)- matching the second example.
Does any of you know a solution or a workaround for this?
Thanks in advance
EDIT:
My service method is as follows
public static async Task<IEnumerable<User>> GetUserById(string id)
{
var json = await client.GetStringAsync($"api/users/{id}");
var users = JsonConvert.DeserializeObject<IEnumerable<User>>(json);
return users;
}
And my service call is
var users = await UserService.GetUserById("Example");
EDIT2: Fixed
Service method changed to
public static async Task<User> GetUserById(string id)
{
var json = await client.GetStringAsync($"api/users/{id}");
var users = JsonConvert.DeserializeObject<User>(json);
return users;
}
It turns out the issue was caused by the IEnumerable type on the task definition, which makes sense since I was trying to retrieve a single instance.
Service method changed to
public static async Task<User> GetUserById(string id)
{
var json = await client.GetStringAsync($"api/users/{id}");
var users = JsonConvert.DeserializeObject<User>(json);
return users;
}
I want to create a method that uploads a file + takes an instance of a class\struct as an additional argument.
// Works
[HttpPost("test_1")]
public async Task<IActionResult> Test1(IFormFile file) { return Ok(); }
public struct MyModel
{
public int Value1 { get; set; }
public int Value2 { get; set; }
}
// Doesn't work
[HttpPost("test_2")]
public async Task<IActionResult> Test2(IFormFile file, MyModel model) { return Ok(); }
Calling test_2 produces following result:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.13",
"title": "Unsupported Media Type",
"status": 415,
"traceId": "8000000c-0007-fd00-b63f-84710c7967bb"
}
How should I modify test_2 method to produce required result?
Because your request contains multi part (file and optional data).
So change it to form-data and you can get them with [FromForm] on Api.
Try this
public struct MyModel
{
public int Value1 { get; set; }
public int Value2 { get; set; }
public IFormFile Files { get; set; }
}
[HttpPost("test_2")]
public async Task<IActionResult> Test2([FromForm]MyModel model) { return Ok(); }
Hope it helps
I am integrating with waboxapp API (link) using ASP.NET Core MVC 2.0.
Some parameters have been posted like this
contact[uid], contact[name], contact[type], message[uid], message[body] etc...
I have tried the following code :
[HttpPost]
public IActionResult Index(string uid, string token, List<string> contact)
{
foreach (string item in contact) {
Common.TestEmail(uid, token);
}
return View();
}
What is the proper way to retrieve incoming parameters?
For waboxapp, its request is Standard HTTP format (application/x-www-form-urlencoded). Try to follow steps below:
Model
public class Waboxapp
{
public string Token { get; set; }
public Contact Contact { get; set; }
}
public class Contact
{
public string Name { get; set; }
public string Type { get; set; }
}
Action
[HttpPost]
public IActionResult WaboxappFromForm([FromForm]Waboxapp waboxapp)
{
return View();
}
Request
Result
I'm trying to insert into a DB using WebAPI for a .Net Core project but it's not working -
[Route("api/IMTWebAPI")]
public class IMTWebAPIController : BaseController
{
[HttpPost("Create")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([FromBody] InterMemberTransfer interMemberTransfer)
{
var testController = new CRUDForIMT(_context);
var response = await testController.Create(interMemberTransfer);
return Json(response);
}
}
CRUDForIMT -
private readonly ARMStocktradeV2Context _context;
public CRUDForIMT(ARMStocktradeV2Context context)
{
_context = context;
}
public async Task<int> Create([Bind("Id,Date,EmailAddress,PhoneNumber,ResidentBroker")] InterMemberTransfer interMemberTransfer)
{
_context.Add(interMemberTransfer);
var res = await _context.SaveChangesAsync();
return res;
}
Anytime I test in postman, i get a 400 bad request and no response.
My Model -
public partial class InterMemberTransfer
{
public long Id { get; set; }
public DateTime Date { get; set; }
public string EmailAddress { get; set; }
public long PhoneNumber { get; set; }
public string ResidentBroker { get; set; }
}
I added a breakpoint in the Create action method but it's not even getting to the breakpoint.
Remove [ValidateAntiForgeryToken] from your Create Method.
Otherwise you'll never get into this Method at all. At least not with Postman.