How can I pass object param to get method in web api? - asp.net-web-api

How can I pass object parameter to get method? I searched a lot ,
for example how to pass parameters to asp.net web api get method?
Here It is mentioned that we should use [FromUri] but I could not see [FromUri] in .NET Core 2
[HttpGet]
public IHttpActionResult GetDetails([FromUri] RetrieveDetails eDetails)
{}
following is the class
public class RetrieveDetails
{
public string Name{ get; set; }
public string Type { get; set; }
public List<MoreDetails> MoreDetails { get; set; }
}
public class MoreDetails {
public string DetailName{ get; set; }
}
But FromUri can not be used in .NET Core 2

Generally, we use POST method to pass an complex type.But you could also do it using [FromQuery] for GET method.
Action:
[HttpGet("Test")]
public async Task<IActionResult> GetDetails([FromQuery]RetrieveDetails eDetails)
Url:
.../Test?eDetails.Name=hello&eDetails.Type=world&eDetails.MoreDetails[0].DetailName=size&eDetails.MoreDetails[1].DetailName=price

Related

Asp.net core 2.2 web api FromForm of complex object contains only null values

Hi I am trying to build an endpoint for slack commands in asp.net core 2.2.
I have a data structure representing a commandrequest from slack like so:
public class SlackCommandDTO
{
[FromForm(Name = "token")]
public string Token { get; set; }
[FromForm(Name = "team_id")]
public string TeamId { get; set; }
[FromForm(Name = "team_domain")]
public string TeamDomain { get; set; }
[FromForm(Name = "channel_id")]
public string ChannelId { get; set; }
[FromForm(Name = "channel_name")]
public string ChannelName { get; set; }
[FromForm(Name = "user_id")]
public string UserId { get; set; }
[FromForm(Name = "user_name")]
public string UserName { get; set; }
[FromForm(Name = "command")]
public string Command { get; set; }
[FromForm(Name = "text")]
public string Text { get; set; }
[FromForm(Name = "response_url")]
public string ResponseUrl { get; set; }
[FromForm(Name = "trigger_id")]
public string TriggerId { get; set; }
}
My controller to receive data looks like this:
[Route("api/[controller]")]
[ApiController]
public class CustomerServiceController : ControllerBase
{
// POST api/customerservice
[HttpPost]
public void Post([FromForm] SlackCommandDTO command)
{
Console.Write(command.Token);
}
}
my startup.cs looks like this
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
I have tried setting the compatability settings in startup.cs to 2.1 and 2.2.
The result is always an instance of the object that contain null in all properties.
I have tried setting the decorator to [FromBody] (not that that is supposed to work) but in that case I get 415 unsupported media type (as it should).
I have tried sending the requests with content-type x-www-form-urlencoded and form-data as well as text/plain and application/json. the latter two return 415.
I have also tried sending the request through swagger with the same result and curl both using -d keyword and -F keyword for each pair of data.
If I am missing some information please let me know, I am drawing a blank here on how to solve it so please help.
The data I am receiving is from Slack according to this article about implementing slash commands in slack.
https://api.slack.com/slash-commands#responding_to_commands
I have solved my problem.
My issue was the fundamental misunderstanding that the parameters would be bound as a single object when using the FromForm attribute when actually I was supposed to parameterize each field as a string input in the post method like so:
[Route("api/[controller]")]
[ApiController]
public class CustomerServiceController : ControllerBase
{
// POST api/customerservice
[HttpPost]
public void Post([FromForm] string token,
[FromForm] string team_id,
[FromForm] string team_domain,
[FromForm] string channel_id,
[FromForm] string channel_name,
[FromForm] string user_id,
[FromForm] string user_name,
[FromForm] string command,
[FromForm] string text,
[FromForm] string response_url,
[FromForm] string trigger_id)
{
Console.Write(token);
}
}
[FromForm] is not for annotating properties on your model. It's for indicating how an action param will be bound. If you were accepting JSON, you could achieve this via [JsonProperty], but there's no way to change the property names for binding from form. They need to match, i.e. you'll either need to change your properties to stuff like Team_Id (with the underscore) or change your field names to stuff like teamId (without the underscore).

Is there something like [Bind(Exclude="Property")] for asp.net web api?

I'm trying to exclude a property from my Post Action in a web api controller, is there something like [Bind(Exclude="Property")] for asp.net web api?
This is my model:
public class ItemModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I want to exclude the Id in the Post Action, because it is autogenerated, but I need to return it in my Get Action.
I Know I could have two models, one for my Post action and one for my Get action, but I'm trying to do this with just one model.
I would favour mapping models but this could be achieved by checking if the request is a POST in a ShouldSerialize method:
public class MyModel
{
public string MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
public bool ShouldSerializeMyProperty2()
{
var request = HttpContext.Current.Request;
if (request.RequestType == "POST") return false;
return true;
}
}
Where your method name is the name of the property prefixed with ShouldSerialize.
Note this will work for JSON. For XML, you will need to add the following line to your config:
config.Formatters.XmlFormatter.UseXmlSerializer = true;
You can simply create a DTO for POST.

Error deserializing JSON to a class with IEnumerable

I need to return a collection with nested optional collections from my WebAPI and convert it back to objects in my Web UI, however I'm getting the following error:
Cannot create and populate list type System.Linq.IQueryable`1[MyNamespace.MyClass].
I'm using Json.Net.
Here is a sample of my code:
public class ClassA
{
public Int64 Id { get; set; }
public String Description { get; set; }
public IEnumerable<ClassB> { get; set; }
}
public class ClassB
{
public Int64 Id { get; set; }
public String Description { get; set; }
}
I've saw some questions here in stackoverflow, but I don't have access to serialization options (it is handled internally by our library).
UPDATE
I've forgot to mention that ClassA is returned as an IQueryable in my Web API.
Changing the return type of my Web API method to IEnumerable instead of IQueryable solved the problem.

Need example for web api post with multiple parameter

In c#, Need example for web api post with multiple parameter ,Below i have attached my sample code.Please look into the InsertLeave method.In my code without CompanyId parameters working fine. When i add the companyid not able to invoke.
namespace AeS.SaaSAPI_2116
{
[RoutePrefix("{CompanyId}/{SecurityKey}")]
public class LeaveController : ApiController
{
[HttpPost]
[Route("{APIName}/x")]
public string InsertLeave(List<LeaveRequest> objList, string CompanyId)
{
foreach (LeaveRequest LR in objList)
{
}
return "Sucess ";
}
}
}
public class LeaveRequest
{
[Required]
public string EMP_STAFFID { get; set; }
[Required]
public string LEAVE_TYPE { get; set; }
}
}
I think you can use send your parameter to the server by request body, You will have to create a single class that wrapping your all parameters.You can use model binding to resolve this kind of issue

How to update a property of an abstract with an inheriting/using a subblass in MVC

I have an abstract class
public abstract class Member
{
public string ID { get; set; }
public string Username { get; set; }
public int MemberType { get; set; }
public abstract string MemberName { get; set; }
public int Status { get; set; }
}
public class Person : Member
{
public string LastName { get; set; }
public string FirstName{ get; set; }
}
public class Business : Member
{
public string BusinessName { get; set; }
public string TaxNo { get; set; }
}
The class was mapped using fluent API,
Now, is there a way to update the "Status" property from the view(having Member model) without using or going to a subclass (Person/Business)?
I just tried it, but it says "Cannot create an abstract class.", when submitting the page.
Or there is a correct way to do this?
Thanks
Not in EF. You have to instantiate an object to work with EF, and you can't instantiate an abstract class.
You could make the class not be abstract. Or you could use a stored proc to update the field, or some direct sql.
It sounds like your problem is that your action method has an abstract type as a parameter, which the default model binder can't do anything with. If you are dead set on using the same view for two different classes, you may need to implement your own model binder to inspect in the incoming request and decide which type, Person or Business, to instantiate.
Check out this link for more information on creating a custom model binder:
http://odetocode.com/blogs/scott/archive/2009/05/05/iterating-on-an-asp-net-mvc-model-binder.aspx
This seems like a similar problem to the one I've answered previously here:
ASP.NET MVC 3: DefaultModelBinder with inheritance/polymorphism

Resources