How to develop an ASP.NET Web API to accept a list object as GET parameter? - asp.net-mvc-4

I have read this link:
How to develop an ASP.NET Web API to accept a complex object as parameter?
And implemented the code just fine. Now I want to convert the 'firstName' parameter to accept an IList<string> collection. I have modified the class like this:
public class MyApiParameters
{
public IList<string> FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
I was hoping that the accepted URL would look like this:
http://localhost:58256/api/articles?firstName=matthew,andrew,philip,david&LastName=smith&birthDate=12-12-2012
But the parameter is only interpreted as a list if I pass it like this:
http://localhost:58256/api/articles?firstName=matthew&firstName=andrew&firstName=philip&firstName=david&LastName=smith&birthDate=12-12-2012

Add [FromUri] attribute annotation before you parameter and pass the second way of passing values you have mentioned in your question.
public MyApiParameters GetTest([FromUri]MyApiParameters test)
{
return test;
}

Related

Swagger and JsonStringEnumConverter at property level

We have a .NET 6 application utilising System.Text.Json and Swashbuckle v6.5.0.
Is there a way to tell Swagger UI to show enum properties as strings instead of ints? I know there are a couple of ways to achieve this:
Declare globally in Program.cs like so: builder.Services.AddControllers().AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); });
Decorate the enum declaration itself with this attribute: [JsonConverter(typeof(JsonStringEnumConverter))].
But both of these approaches are too global, one should be able to control this at an individual enum property level by decorating it with the [JsonConverter(typeof(JsonStringEnumConverter))] attribute like so:
public record Address
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public AddressType? AddressType { get; set; }
public string? CompanyName { get; set; }
public string? AddressLine { get; set; }
}
I think this is something that Swashbuckle or Swagger needs to fix up on their end. But apart from that, are there any other suggestions?

How to bind a collection with objects?

I need to bind a collection of objects from a querystring, but I cannot find the proper querystring format.
My controller code:
public class Filter
{
public string Name { get; set; }
public string Operator { get; set; }
public object Value { get; set; }
}
public void Get(IEnumerable<Filter> filters)
{
....
}
If you do want to pass the objects with querystring you could try as below:
https://localhost:44389/Test/Index?filters[0].Name=n1&filters[1].Name=n2&filters[2].Name=n3&filters[2].Value=v3
The result:
the offcial document related:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-6.0#collections
but i don't think it's a good solution,because the length of Url is limited,if your model has plenty properties and your collection has many elements ,you may get some error

.Net 5 - API JsonProperty

I have a [HttpPost] function in API Controller, that has this definition:
public async Task<IActionResult> Test([FromBody] TestData testData)
I tried to use many atributes anotations in my class TestData [JsonProperty("")], [JsonPropertyName("")], [JsonObject].
I used libraries - Newtonsoft.Json and System.Text.Json.Serialization. But the testData always included null. The API works when I put a body with same name of atribute has. Soo I expect, I am missing something in my Configuration.
I even try to add services.AddControllersWithViews().AddNewtonsoftJson() . Nothing changed.
How does it make it work in .Net 5 ?
#jps
public class TestData
{
[JsonIgnore]
public int Id { get; set; }
[JsonIgnore]
public string UserId { get; set; }
[JsonPropertyName("test_number")]
public long Number { get; set; }
...
}
When I post a body {"test_number":"123456"} on http://.../Test . I see testData.Number = null
I feels like, the JsonPropertyName works only for Serialization , and not for
Deserialization
Solved, There was an issue with Docker.

.NET CORE API: Is it possible to conditionally validate a model depending on the http verb used to submit it?

I'm very new to the FluentValidation and I'd like to validate my model in different ways depending on which verb was used to submit it.
Given a very simple class, I'd like to ignore the ID property on a POST but ensure it's been provided on a PUT. Is this something the FluentValidation can do?
public class CategoryModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I'm guessing I have to get the HttpContext over to the validators so I can determine the http method used, but I don't want to re-invent the wheel if there's already a built-in way.
Thanks!!
I think I've come up with a solution by passing the context to my validator. However, if something looks wrong or out of place, please let me know.
public class CategoryModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class CategoryModelValidator : AbstractValidator<CategoryModel>
{
public CategoryModelValidator(IHttpContextAccessor context)
{
if (context.HttpContext.Request.Method == HttpMethods.Post)
RuleFor(x => x.ID).Empty();
if (context.HttpContext.Request.Method == HttpMethods.Put)
RuleFor(x => x.ID).NotEmpty();
RuleFor(x => x.Name).Length(1, 30);
}
}
Passing the context was easier than I thought. All I had to do was register it in my ConfigureServices method with services.AddHttpContextAccessor() and DI takes care of the rest.
To be honest, this is a pretty handy validation tool

Delegate the property display name translation to a handler

Current code in model:
[Display(Name = "E-mail")]
public string EMail { get; set; }
Desired code:
public string EMail { get; set; }
I would like to delegate the translation to a handler, something like this:
if(propertyName == "EMail") return "E-mail"
Based on my understanding of your question, I'm assuming that you are trying to implement localisation in your application.
If so, there are two options;
Resources
In .NET you can add Resource (.resx) files into your application to handle translation (one resx for each language). Then you can specify the Resource by specifying the ResourceType property of your Display attribute. For example;
public class Model
{
[Display(Name = "Email", ResourceType = typeof(Resources.Strings))]
public string Email { get; set; }
}
Custom attribute
Alternatively, if you are set on implementing this in a handler then you could implement a custom attribute, as demonstrated in this question.
Edit: Modified from the example in the above post.
If you add a new Resource file to your project - say Strings.resx and add "HelloWorld" as a field. You can then create a new attribute, such as LocalisedDisplayNameAttribute;
public class LocalisedDisplayNameAttribute : DisplayNameAttribute
{
public LocalisedDisplayNameAttribute(string resourceId)
: base(GetMessageFromResource(resourceId))
{
}
private static string GetMessageFromResource(string resourceId)
{
// "Strings" is the name of your resource file.
ResourceManager resourceManager = Strings.ResourceManager;
return resourceManager.GetString(resourceId);
}
}
You can then use it as follows;
public class Model
{
[LocalisedDisplayName("HelloWorld")]
public string Email { get; set; }
}
Let me know if I can help further,
Matt