Json object using WebAPI controller - asp.net

I am using webapi controller.I have to pass an JSON object from Java applet to web api controller. How to write a web api controller method to accept the JSON object
public test GetPo(int id)
{
}

ASP.NET Web API uses JSON format as default format:
JSON formatting is provided by the JsonMediaTypeFormatter class. By default, JsonMediaTypeFormatter uses the Json.NET library to perform serialization. Json.NET is a third-party open source project.
what you just do is to defined your model object which map with json:
public class Model
{
public int Property1 { get; set; }
public string Property2 { get; set; }
// More properties
}
And your POST method:
public void Post(Model model)
{}

Related

Refit API Client - Mix Body and Queryparameters in single object

When using the Refit REST Library to build a client targeting an asp.net based api is it possible to mix Query and Body items in a single Custom Object?
Example Asp.Net Route
[Route("documents/{id}")]
public void PostDocument(int id, [FromBody] document)
Example Refit Client and Request Object showing desired mixing of Body and Query definition in single object
[Post("/documents/{document.id}}")]
Task PostDocument(PostDocumentRequest request);
public class PostDocumentRequest
{
public int Id {get;set;}
public [Query] DateTime? LocalDateTime {get;set;}
public [Body] Document Document {get;set;}
}

Swagger UI doesn't render body parameter field for my complex type parameter in GET action of my Controller

I have an ASP.NET Web API 2 project to which I have added Swagger - Swashbuckle v5.6.0. Everything works fine. Swagger UI renders test endpoints for my API as expected.
I added a new Controller to my API. There is a GET action with a complex type parameter. For complex types, Web API tries to read the value from the message body. This is the default behaviour.
Here is my GET action:
[HttpGet]
[Route("search")]
[ResponseType(typeof(List<SearchModel>))]
public IHttpActionResult Search(SearchModel searchOptions)
{
//....
return Ok();
}
And her is my complex type:
public class SearchModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string Email { get; set; }
public string AddressLine1 { get; set; }
public string City { get; set; }
public string Telephone { get; set; }
public string MobilePhone { get; set; }
}
The problem:
But Swagger UI doesn't render body parameter field for my complex type in the GET action. For POST and PUT actions Swagger UI renders body parameter fields as expected but not for the complex type in my GET action.
As can be seen in the screenshot Swagger UI renders query parameters fields for attributes in my complex type instead of rendering a body parameter field for my type as it does in the case of POST and PUT.
My GET action is working fine when testing from Postman and filling the json in the body of the request. By setting breakpoint in the action inside Visual Studio I can see the values are bound to my object in the action parameter.
I have tried to decorate the parameter in my action with [FromBody] (which is the default for complex type) but same result.
Is this a bug in Swagger? Or am I missing something?
Sadly, you can't do what you want with Swagger. You can't send a request model in an HTTP GET method. You can however change the swagger UI to look like this:
but you won't be able to receive the model in your controller.
This is a known issue within the Swagger developers and it was discussed in 2016 and the final decision is that swagger won't support a request body in an HTTP GET method. Here is the link to the already closed issue.
You have three options here:
Leave the method as it is, and test it in Postman, but not in Swagger.
Follow the below steps to achieve the picture above, but please note, that it will only fix the UI part and you will always end up with null SearchModel in the controller when you press Try it out! in swagger.
Make it a [HttpPost method instead of [HttpGet].
How to make swagger UI display GET method with request body:
First, create one Attribute class:
public class ModelInBodyAttribute : Attribute
{
public ModelInBodyAttribute(string modelName, string description, bool isRequired)
{
this.ModelName = modelName;
this.Description = description;
this.IsRequired = IsRequired;
}
public string ModelName { get; set; }
public bool IsRequired { get; set; }
public string Description { get; set; }
}
Then you can decorate your method in the controller:
[ModelInBody(modelName: nameof(SearchModel), description: "My model description", isRequired: true)]
[HttpGet]
[Route("search")]
[ResponseType(typeof(List<SearchModel>))]
public IHttpActionResult Search(SearchModel searchOptions)
{
//....
return Ok(new List<SearchModel>());
}
After that create IOperationFilter class (ModelInBodyOperationFilter):
public class ModelInBodyOperationFilter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var attribute = apiDescription.GetControllerAndActionAttributes<ModelInBodyAttribute>().FirstOrDefault();
if (attribute == null)
{
return;
}
operation.parameters.Clear();
operation.parameters.Add(new Parameter
{
name = attribute.ModelName,
description = attribute.Description,
#in = "body",
required = attribute.IsRequired,
schema = new Schema { #ref = $"#/definitions/{attribute.ModelName}" }
});
}
}
Lastly, don't forget to register the IOperationFilter in SwaggerConfig:
c.OperationFilter<ModelInBodyOperationFilter>();
When you send the request via swagger, you will notice that the Curl part is absolutely correct, but still, in your controller there is nothing.
There are endless discussions on whether you should have a PAYLOAD "Body content" in a GET request. As you mentioned it's supported by HTTP but you will find in the internet that many people suggest not to do it. I guess that swagger team also expect you not to use it.

How to add custom authorization filter to method not controller in asp net core?

When I add custom IAuthorization attribute to controller method it works, but when I add it to method that is not part of controller method, IAuthorization method does not execute. Why?
public interface ICasbinBLL
{
public abstract string objectId { get; set; }
[ClaimRequirement("userId", "delete")]
string DeleteMonitoring();
}
public class CasbinBLL : ICasbinBLL
{
public string objectId { get; set; }
[ClaimRequirement("userId", "delete")]
public string DeleteMonitoring()
{
return objectId;
}
}
IAuthorizationFilter is one of the filters in ASP.NET Core. Filters are executed by ASP.NET Core framework in filter pipeline.
Filters run within the ASP.NET Core action invocation pipeline, sometimes referred to as the filter pipeline. The filter pipeline runs after ASP.NET Core selects the action to execute.
If you add filters to your own types, ASP.NET Core does not know how to execute them.

Make an XML element mandatory

Here I am currently working on a program that will serialize an XML file asp.net object. My problem is that I can not find the attribute that makes it mandatory to have a tag in the XML file.
You will find below the definition of my object.
[System.SerializableAttribute()]
public class EchangeIdentification
{
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("agrement")]
public string Agrement{ get; set; }
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("cvi")]
public string NumeroCvi { get; set; }
/// <remarks/>
[Required]
[XmlElement("siret")]
public string Siret { get; set; }
}
As far as I know, there is no way to declaratively force elements and attributes to be required using the XmlSerializer. C# object properties that can be null are always optional.
A few observations
[Serializable] is not used by the XML Serializer.
There is no way to make it required using the XML Serializer, but if you don't have to use XmlSerializer? DataContractSerializer provides the following option:
[DataMember(IsRequired = true)]
You don't need the "Attribute" name in the code, your code could look like this
[Serializable]
public class EchangeIdentification
{
[XmlElement("agrement")]
public string Agrement{ get; set; }
[XmlElement("cvi")]
public string NumeroCvi { get; set; }
[XmlElement("siret")]
public string Siret { get; set; }
}
Define "serialize an XML file asp.net object" and "makes it mandatory to have a tag in the XML". It all depends on how you're using this class.
Are you using it as a deserialization container, into which you will deserialize XML you receive? Then create an XSD schema, and validate the incoming XML before (or rather during) serialization. See Validating an XML against referenced XSD in C#.
On the other hand, if the user of this code is assigning properties of an instance of this class at runtime, and you serialize it through XmlSerializer, you could validate the output after serializing. See the linked question above, and Can I fail to deserialize with XmlSerializer in C# if an element is not found?.
Alternatively, you could implement serialization callbacks and create a validation method that throws an exception if [Required] properties have the default value for their type.
I'd go with the XSD route either way.

Deserializing JSON objects as List<type> not working with asmx service

I am having trouble deserializing my JSON string. I have a class of type person with public properties for sequence number of type int, first name, and last name. I want to pass an array of these objects in JSON format and have them deserialized as a list so I can loop through them on the server, but ASP.NET says something about not being supported to be deserialized as an array. I have validated the JSON I am producing, and it is valid. Is there something special about the JSON that ASP.NET needs to have before it can deserialize? The funny thing is if I serialize a list<person> object to JSON it looks exactly like the JSON I am producing. I must be missing something... To clarify, I'm using the ASP.NET Ajax library to deserialize. This is what I get back from the web service:
{"Message":"Type \u0027System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\u0027 is not supported for deserialization of an array."
Actually unfortunately this doesn't seem to have anything to do with deserializing, it appears that you can't pass an array of JSON objects to an asmx web service. Am I correct? If you can't do that, is it possible to pass a collection of JSON objects to a web service and have them processed on the server with ASP.NET and C#?
Update:
OK, here is my code. Here is the person class:
public class person
{
public person()
{
//
// TODO: Add constructor logic here
//
}
public int seq
{
get;
set;
}
public string firstName
{
get;
set;
}
public string lastName
{
get;
set;
}
}
And here is my JSON string:
[{"seq":1,"firstName":"Chris","lastName":"Westbrook"},
{"seq":2,"firstName":"sayyl","lastName":"westbrook"}]
And here is the code I'm using
[WebMethod]
public void updatePeople(string json)
{
IList<person> people =
new JavaScriptSerializer().Deserialize<IList<person>>(json);
//do stuff...
}
I figured it out. I wasn't wrapping my JSON in an object like ASP.NET Ajax requires. For future viewers of this question, all JSON objects must be wrapped with a main object before being sent to the web service. The easiest way to do this is to create the object in JavaScript and use something like json2.js to stringify it. Also, if using an asmx web service, the objects must have a __type attribute to be serialized properly. An example of this might be:
var person=new object;
person.firstName="chris";
person.lastName="Westbrook";
person.seq=-1;
var data=new object;
data.p=person;
JSON.stringify(data);
This will create an object called p that will wrap a person object. This can then be linked to a parameter p in the web service. Lists of type person are made similarly, accept using an array of persons instead of just a single object. I hope this helps someone.
Could you show the JSON string you are trying to deserialize and the way you are using the Deserialize method? The following works fine:
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace Test
{
class Program
{
class Person
{
public int SequenceNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public static void Main()
{
string json = "[{\"SequenceNumber\":1,\"FirstName\":\"FN1\",\"LastName\":\"LN1\"},{\"SequenceNumber\":2,\"FirstName\":\"FN2\",\"LastName\":\"LN2\"}]";
IList<Person> persons = new JavaScriptSerializer()
.Deserialize<IList<Person>>(json);
Console.WriteLine(persons.Count);
}
}
}
Or even simpler, when you are doing the $.ajax(...) use
data:"{\"key\":"+JSON.stringify(json_array)+"}",
and then on the other side of the code, make your function use the parameter "object key"
[WebMethod]
public static return_type myfunction(object key){...}
SERVER SIDE
[WebMethod]
public void updatePeople(object json)
CLIENT SIDE
var person = "[{"seq":1,"firstName":"Chris","lastName":"Westbrook"}
,{"seq":2,"firstName":"sayyl","lastName":"westbrook"}]";
var str = "{'json':'" + JSON.stringify(person) + "'}";
I think the problem is what type you have to deserialize. You are trying to deserialize type
IList
but you should try to deserialize just
List
Since interface can not be instantiated this might is the root problem.

Resources