Passing Object as an parameter in Web Api - asp.net

In Web Api How can pass object as parameter
// GET api/values/{can be any serilizable object}
public string Get(object data)
{
return "value";
}
[Serializable]
public class RequestData
{
public string Id { get; set; }
public string Name { get; set; }
}

Your object will have to be sent in the request as JSON. [Serializable] is different kind of serialization. Here we talking either JSON or XML serialization and it is built-in
public HttpResponseMessage Get(RequestData requestData)
{
HttpResponseMessage retMsg;
// pack your message here, select serializer {json, xml}, etc
return respMessage;
}
// [Serializable] - not needed, good old POCO is fine
public class RequestData
{
public string Id { get; set; }
public string Name { get; set; }
}

Related

ASP.Net API how to let API accept an IFromFile and an object at the same API call

I have the following API that works properly
[HttpPost("testing")]
public string Testing(IFormFile file, string str, int num)
{
return str + num.ToString();
}
What I want to do ideally is to pass "str" and "num" in an object instead of each param on its own
Like this:
public class Testdto
{
public int Num{ get; set; }
public string Str { get; set; }
}
[HttpPost("testing")]
public string Testing(IFormFile file, Testdto dto)
{
return dto.Str + dto.Num.ToString();
}
Of course the above format rends an error, it does not work.
Is there a way to make it work? My real API body is quite large and contains nested objects so I can't just pass them all as params in the API
add the FromForm Attribute :
[HttpPost("testing")]
public string Testing(IFormFile file, [FromForm]testdto dto)
{
return dto.str + dto.num.ToString();
}
And add the parameters to request form
The result:
You can also create class having properties as IFormFile and other fileds.
And pass it to your controller with [FromForm] attribute
Sample Code:
[HttpPost]
[Route("FileUpload")]
public ActionResult FileUploaded([FromForm] PostRequest postRequest)
{
return Ok(postRequest.str);
}
public class PostRequest
{
public int Num { get; set; }
public string Str { get; set; }
public IFormFile File { get; set; }
}

Troubleshooting model binding problem in ASP.NET Core 3.1 API

I'm trying to send an object via a POST request to my ASP.NET Core 3.1 API but I keep getting Bad Request error. As far as I can see, I do have a class that matches what I'm expecting perfectly but clearly it's not. How can I see exactly what the problem is?
The following fails:
public async Task<IActionResult> Post([FromBody] MyCustomObject input)
{
// Do something here...
}
If I use a dynamic, it works fine. So the following code works fine:
public async Task<IActionResult> Post([FromBody] dynamic input)
{
// Do something here...
}
As I said, I'm just getting a 400, Bad Request error. I've been going over MyCustomObject again and again and it looks identical to the object that I'm sending.
Here's what my custom class looks like:
public class CreateContactVm
{
[GuidEmptyNotAllowed]
public Guid AccountId { get; set; }
[Required]
public string AccountName { get; set; }
[GuidEmptyNotAllowed]
public Guid ContactGroupId { get; set; }
[IntZeroNotAllowed]
public int ContactType { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string EntityName { get; set; }
public List<AddEmailVm> Emails { get; set; } = new List<AddEmailVm>();
public List<AddPhoneNumberVm> PhoneNumbers { get; set; } = new List<AddPhoneNumberVm>();
public List<AddAddressVm> Locations { get; set; } = new List<AddAddressVm>();
}
Here, I use some custom validations such as [GuidEmptyNotAllowed] or [IntZeroNotAllowed]. I inspect the object I send via my POST call and it satisfies ALL of these requirements and yet it still fails.
How can I get more information about why my API method is throwing a 400 error?
UPDATE:
The following code allows me to convert what comes in as a dynamic to my CreateContactVm custom class but I really shouldn't have to do this at all:
CreateContactVm request = new CreateContactVm();
try
{
var element = (JsonElement)input; // input is the dynamic received
request = JsonUtils.Deserialize<CreateContactVm>(element.GetRawText());
}
catch(Exception e)
{
var error = e.Message;
}
This also proves that the issue is with model binding. Something in my custom class is not liking the JSON object it receives.

Looking for a way to change http request and add user id on body data

I am working on a web API where login is required in order to do any other action, so I am using identity with role-based authentication.
What I would like to achieve is to override the user id into the request body before the controller's action only in cases where the request type implements a certain interface.
For example, I have these view model
public class UserVM : IVMLogging {
public Guid? ID { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public bool IsActive { get; set; }
public Guid Role { get; set; }
public string LastModifiedBy { get; set; }
}
public class OptionVM : IVMLogging {
public Guid? ID { get; set; }
public string Name { get; set; }
public string LastModifiedBy { get; set; }
}
And this interface
public interface IVMLogging {
string LastModifiedBy { get; set; }
}
In both cases property LastModifiedBy is where I want store the user id (ignoring the value coming from client).
Is this possible to be done?
While you can use middleware to modify an inbound request on the way to the controller, the work to try to inspect, serialize, and deserialize the body type is probably more trouble than it's worth. Your controllers can modify the contents of the view model on return if there are any properties that you'd like to update, like attaching the user:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
[HttpPost]
public IActionResult Post(Foo foo)
{
foo.Qux = HttpContext.User.Identity.Name; // Use the identity name
foo.Qux = HttpContext.User.FindFirst("claimName").Value; // grab a claim value
// do whatever actions
}
...
Your controller will have access to the HTTP context and can grab the current identity or claims and add them where you want them before you process your viewmodel.
If this is something you find yourself doing regularly, you could add an extension for it for your interface:
public static class FooExtensions
{
public static IFoo SetFooUser(this IFoo foo, ClaimsPrincipal claimsPrincipal)
{
foo.Qux = claimsPrincipal.Identity.Name;
return foo;
}
}
Which can then be called more simply with foo.SetFooUser(HttpContext.User) in your controller as long as it implements the interface.

web api method to return data in json format?

I am making a web api call and I want the controller method to return data in json format.
The model class I used is User.cs :
public partial class User
{
public int UserID { get; set; }
public string city { get; set; }
public string email { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string phone { get; set; }
public string password { get; set; }
}
I want to return all the users email data in json format through the following controller method.
public string GetUsers()
{
IEnumerable<User> users = db.Users.ToList();
var jsonSerialiser = new JavaScriptSerializer();
var json = jsonSerialiser.Serialize(users);
return json;
//string json = JsonConvert.SerializeObject(users);
//return json;
}
All I am getting is empty json like:
[]
Please help. I have covered all the methods recommended on stackoverflow.
This is a lot simpler than you think, you do not need to use a jsonSerializer.
You can change your method to the following:
public List<string> GetEmails()
{
return db.Users.Select(e => e.email).ToList();
}
Then if the client specifies application/json the content is returned as json.
Please note with the above, I am only sending back the email address and not the full user details as I very much doubt you will want to send passwords out as json.

ASP.NET web API casting http response to json array

My Code works fine when calling REST URL:
http://api.feedzilla.com/v1/categories.json
but when I call following URL I get error:
http://api.feedzilla.com/v1/categories/15/articles.json?count=36&since=2012-11-15&client_source=&order=relevance&title_only=0&
Error:
{"Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.IEnumerable`1[Nitin.News.DAL.Resources.Article]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath 'articles', line 1, position 12."}
My Code is as follows:
public class Article
{
public string publish_date { get; set; }
public string source { get; set; }
public string source_url { get; set; }
public string summary { get; set; }
public string title { get; set; }
public string url { get; set; }
}
public IEnumerable<Article> Get()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://api.feedzilla.com/v1/");
//Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// call the REST method
HttpResponseMessage response = client.GetAsync("http://api.feedzilla.com/v1/categories/2/articles.json??count=36&since=2012-11-15&client_source=&order=relevance&title_only=0&").Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
return response.Content.ReadAsAsync<IEnumerable<Article>>().Result;
//wont work
//string JSON =response.Content.ReadAsStringAsync().Result;
//return JsonConvert.DeserializeObject<IEnumerable<T>>(JSON);
}
else
{
throw new Exception(string.Format("Data access faild,{0} ({1}) method:{2}", (int)response.StatusCode, response.ReasonPhrase, MethodURL));
}
}
You need another level in your object hierachy... i.e. a root to contain the IEnumerable.
Runing the JSON into the tool at http://json2csharp.com/ generates the following proxy classes:
public class Enclosure
{
public int length { get; set; }
public string media_type { get; set; }
public string uri { get; set; }
}
public class Article
{
public string author { get; set; }
public string publish_date { get; set; }
public string source { get; set; }
public string source_url { get; set; }
public string summary { get; set; }
public string title { get; set; }
public string url { get; set; }
public List<Enclosure> enclosures { get; set; }
}
public class RootObject
{
public List<Article> articles { get; set; }
public string description { get; set; }
public string syndication_url { get; set; }
public string title { get; set; }
}
You just need to change your code to this then:
// Parse the response body. Blocking!
return response.Content.ReadAsAsync<RootObject>().Result.articles;
Obviously strip out any properties you dont need. Just thought I would show them all out of interest.

Resources