I want to remove highlighted node from WEB API request and response.
Below are the class Models used in web api
[DataContract(Namespace = "")]
public class ValidateRequest
{
[DataMember]
public string Client_Code { get; set; }
[DataMember]
public string ClientValidateNo { get; set; }
[DataMember]
public string UserID { get; set; }
[DataMember]
public string Password { get; set; }
}
[DataContract(Namespace = "")]
public class ValidateResponse
{
}
I want to remove highlighted node from WEB API request and response.
Below are the class Models used in web api
To achieve this function, first you need to create a class that inherits from XmlSerializerOutputFormatter:
public class XmlSerializerOutputFormatterNamespace : XmlSerializerOutputFormatter
{
protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
{
//applying "empty" namespace will produce no namespaces
var emptyNamespaces = new XmlSerializerNamespaces();
emptyNamespaces.Add("", "any-non-empty-string");
xmlSerializer.Serialize(xmlWriter, value, emptyNamespaces);
}
}
Then, add the following service in ConfigureServices in startup.cs:
services
.AddMvc(options =>
{
options.OutputFormatters.Add(new XmlSerializerOutputFormatterNamespace());
}).AddXmlSerializerFormatters();
In api method:
[Produces("application/xml")]
public IActionResult GetXml(ValidateRequest request)
{
ValidateResponse response = new ValidateResponse()
{
Amount = 100,
ClientValidateNo = request.ClientValidateNo,
Client_Code = request.Client_Code,
DepositorCity = "aaa",
DepositorName = "das",
DepositorState = "sadasd",
Status = "fasfas"
};
return Ok(response);
}
The test result:
Related
I'm creating a new Route to my WebApi, which should receive the following XML throught a HTTP POST
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AcquireKeysRequest>
<version>2</version>
<content>
<id>MTV</id>
<type>VOD</type>
</content>
<protection>
<protection-system>
<type>DASH-CENC</type>
<system-id>urn:mpeg:dash:mp4protection:2011</system-id>
</protection-system>
</protection>
<key-timing>
<position>0</position>
</key-timing>
</AcquireKeysRequest>
I've mapped it through the framework, using the following Model:
public class AcquireKeysRequest
{
public int Version { get; set; }
public Content Content { get; set; }
public Protection Protection { get; set; }
public KeyTiming KeyTiming { get; set; }
}
public class Content
{
public string Id { get; set; }
public string Type { get; set; }
}
public class Protection
{
public ProtecionSystem ProtectionSystem{ get; set; }
}
public class ProtecionSystem
{
public string Type { get; set; }
public string SystemId { get; set; }
}
public class KeyTiming
{
public int Position { get; set; }
}
When I receive the request without the header
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
The mapping works just fine, but when I add the header, it breaks.
How can I ignore it?
[HttpPost]
[Route("{instanceId}")]
public object AcquireKeyRequest([FromUri]int instanceId, AcquireKeysRequest xml)
{
//SomeLogicHere
}
P.S: I know that the names in the Model and in the XML are diferent, I fixed in my code already.
Within your MVC Web API project please add the following package via NuGet:
Microsoft.AspNetCore.Mvc.Formatters.Xml
Then in your startup.cs. Adapt the following to generally enable XML serialization and deserialization.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new ProducesAttribute("application/xml"));
}).AddXmlSerializerFormatters();
}
Finally create a Get and Post Method withing a controller and try it out. For me both cases works. With or without the xml-tag.
[HttpGet]
public AcquireKeysRequest Get()
{
AcquireKeysRequest req = new AcquireKeysRequest();
req.KeyTiming = new KeyTiming() { Position = 2 };
req.Protection = new Protection()
{
ProtectionSystem = new ProtecionSystem() {
SystemId = "wkow", Type = "type"
}
};
req.Version = 2;
req.Content = new Content() { Id = "id", Type = "type" };
return req;
}
[HttpPost]
public void Post([FromBody]AcquireKeysRequest value)
{
}
I hope i could help out.
Cheers
I've been struggling a lot with that, I found some questions but none could answer my needs. I will try to post a better question and some of the things I tried.
Here is the situation:
I have an APIGateway and a WebApp. The WebApp sends POST requests to the APIGateway, so far so good. I use the FromBody attribute to send larger objects, and that was fine too until I introduced interfaces :))
Here's some code:
WebApp:
public interface ICommand
{
Guid CorrelationId { get; set; }
Guid SocketId { get; set; }
}
public class Command : ICommand
{
public Command(Guid CorrelationId, Guid SocketId)
{
this.CorrelationId = CorrelationId;
this.SocketId = SocketId;
}
public Guid CorrelationId { get; set; } = new Guid();
public Guid SocketId { get; set; } = new Guid();
}
public interface IDocument
{
Guid Id { get; set; }
ulong Number { get; set; }
}
public class Document : IDocument
{
public Guid Id { get; set; } = new Guid();
public ulong Number { get; set; } = 0;
}
public interface ICreateDocumentCommand : ICommand
{
IDocument Document { get; set; }
}
public class CreateDocumentCommand : Command, ICreateDocumentCommand
{
public CreateDocumentCommand(IDocument Document, ICommand Command) : base(Command.CorrelationId, Command.SocketId)
{
this.Document = Document;
}
public IDocument Document { get; set; }
}
APIGateway:
[HttpPost]
public async Task<IActionResult> Create([FromBody]CreateDocumentCommand documentCommand)
{
if (documentCommand == null)
{
return StatusCode(403);
}
return Json(documentCommand.Document.Id);
}
Use case:
public class InventoryList : Document
{
public Guid WarehouseId { get; set; } = new Guid();
}
// Example document class
////////////////////////////////////////
// Example POST Request
ICommand command = new Command(messageId, socketId);
switch (item.GetType().Name)
{
case "InventoryList":
command = new CreateDocumentCommand((InventoryList)item, command);
break;
}
string result = await PostAsync($"{apiGatewayAddress}{item.GetType().BaseType.Name}/Create", command, accessToken);
My POST sending function:
public async Task<string> PostAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
{
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, uri);
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item, typeof(T), jsonSerializerSettings), System.Text.Encoding.UTF8, "application/json");
return await _client.SendAsync(requestMessage).Result.Content.ReadAsStringAsync();
}
As you can see I have included TypeNameHandling.All in the JSON serialization settings, the request is sent and the Create in the APIGateway gets called. However the parameter documentCommand is NULL.
I've read this: Asp.Net Core Post FromBody Always Null
This: ASP.NET Core MVC - Model Binding : Bind an interface model using the attribute [FromBody] (BodyModelBinder)
This: Casting interfaces for deserialization in JSON.NET
Tried all kind of magic tricks, created new constructors, marked them with [JSONConstructor], still no success. Also I tried changing the APIGateway Cerate method parameter type to ICreateDocumentCommand and again I got a null. I've been searching some model binding tricks online however I couldn't find anything for binding with FromBody. I also found some solution including DI but I am looking for a simple solution. I hope that we will be able to find one :)
Turns out, passing interfaces or classes with interfaces inside as JSON is not that easy. I added a custom JSONConverter and it works now!
I'm adding an API controller to my MVC application to retun JSON data
In my application I have a class called Album:
public class Album
{
public int Id { get; set; }
public string AlbumName { get; set; }
public int YearReleased { get; set; }
public string AlbumInfo { get; set; }
public string imgAlbumCover { get; set; }
}
My database contains a table of several Album objects
I created an API controller to return this list of Albums in Json format.
I added the following code to WebApiConfig.cs to get JSON back instead of XML:
using System.Net.Http.Headers;
GlobalConfiguration.Configuration.Formatters
.JsonFormatter.MediaTypeMappings.Add
(new System.Net.Http.Formatting.RequestHeaderMapping("Accept",
"text/html",
StringComparison.InvariantCultureIgnoreCase,
true,
"application/json"));
When I do an Albums API call in the browser, returned is a list of Album objects in JSON format.
Instead of returning the list of Albums, I'd like to retun a RootObject that has 1 property called Albums, where Albums is a list of Album objects. Is there a way of doing this in the controller? I don't want to have to create a new RootObject class.
Below is the code for my API controller:
namespace Music.Controllers.API
{
public class AlbumsController : ApiController
{
private MusicContext db;
public AlbumsController()
{
db = new MusicContext();
}
public IEnumerable<Album> GetAlbums()
{
return (db.Albums.ToList());
}
}
}
Then create a viewmodel as such and return the same like
public class AlbumListResponseModel
{
public IEnumerable<Album> Albums { get; set; }
}
public async Task<IActionResult> GetAlbums()
{
AlbumListResponseModel model = new AlbumListResponseModel
{
Albums = db.Albums;
}
return OK(model);
}
If you are using WEB API 2.0 then consider using IActionResult rather
Change the GetAlbums return type to HttpResponseMessage and change the return statement as
return Request.CreateResponse(HttpStatusCode.OK, new {Albums = db.Albums.ToList() });
That's way you don't need to create a new class.
Full Code :
namespace Music.Controllers.API
{
public class AlbumsController : ApiController
{
private MusicContext db;
public AlbumsController()
{
db = new MusicContext();
}
public HttpResponseMessage GetAlbums()
{
return Request.CreateResponse(HttpStatusCode.OK, new {Albums = db.Albums.ToList() });
}
}
}
I just realized that the mapping between the JSON send from a query and my API is not strict.
I give you more explanations:
Here is my C# POCO
public partial class AddressDto
{
public string AddrId { get; set; }
public string Addr1 { get; set; }
public string Addr2 { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
And the REST JSON query
PUT http://Localhost:55328/api/ClientAddr/ADD-2059-S002 HTTP/1.1
content-type: application/json
{
"AddrID": "ADD-2059-S002",
"addr1": "B-1/327",
"addr2": "1ST FLOOR",
"city": "Paris",
"Zip_Code": "78956",
"country": "France",
}
The web client send a PUT with Zip_Code in place of PostalCode. PostalCode is not madatory/required. But Zip_Code does not exist in my DTO.
So in my C# code testing the model state won't help.
public HttpResponseMessage Put(string id, AddressDto address)
{
if (!ModelState.IsValid)
return BadRequest(ModelState); // This wont help
}
How can I raise exception when the client is using something in the JSON that is not existing in my DTO (model) ?
if you need to identify extra columns and handle that as an error you have to extend IModelBinder interface and tell json deserializer to treat extra column as an error and add that error to ModelState. By that way you can check in controller for ModelState.IsValid. Checkout the below Code
CustomModelBinder
public class CustomModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.MissingMemberHandling = MissingMemberHandling.Error;
ObjToPass obj = new ObjToPass();
;
try
{
ObjToPass s =
JsonConvert.DeserializeObject<ObjToPass>(actionContext.Request.Content.ReadAsStringAsync().Result,
settings);
bindingContext.Model = obj;
}
catch (Exception ex)
{
bindingContext.ModelState.AddModelError("extraColumn", ex.Message);
}
return true;
}
}
public class CustomerOrderModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(System.Web.Http.HttpConfiguration configuration, Type modelType)
{
return new CustomModelBinder();
}
}
Object Class that is passed to webapi
public class ObjToPass
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller
[HttpPost]
public void PostValues([ModelBinder(typeof(CustomerOrderModelBinderProvider))] ObjToPass obj)
{
if(!ModelState.IsValid)
{ }
else
{
}
}
This sample holds good for HttpPut as well.
"Over-Posting": A client can also send more data than you expected. For example:
Here, the JSON includes a property ("Zip_Code") that does not exist in the Address model. In this case, the JSON formatter simply ignores this value. (The XML formatter does the same.)
https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api
I'm using the ASP.Net Web API to build a RESTful Service. I'm struggling to find a clean way to add HATEAOS links into the json returned to my clients.
For example I have
public class LongRequest
{
public int Id {get;set;}
public int Progress {get;set;}
}
public HttpResponseMessage Post(LongRequest request)
{
var response = Request.CreateResponse(HttpStatusCode.Accepted, request);
string uri = Url.Link("DefaultApi", new { Id = request.Id });
response.Headers.Location = new Uri(uri);
return response;
}
I want my returned json to include a Cancel and Self link in the json that looks like
'
{
"LongRequest":{
"Id":"32",
"Progress":"33",
"link":{
"rel":"self",
"href":"/LongRequest/32"
},
"link":{
"rel":"cancel",
"href":"/LongRequest/32"
},
}
}
'
What I've done right now is created a link class.
public class Link
{
public string method { get; set; }
public string href { get; set; }
}
and modified LongRequest to be
public class LongRequest
{
public int Id {get;set;}
public int Progress {get;set;}
public Link self
{
get{
return new Link(){href="/Status/"+Id,method="GET"};
}
}
public Link cancel
{
get{
return new Link() { href = "/Status/" + Id, method = "DELETE" };
}
}
}
Which results in json that looks like
{
"Id":0,
"Progress":1,
"self":{"method":"GET","href":"/Status/0"},
"cancel":{"method":"DELETE","href":"/Status/0"}
}
If you want to include links in a standardized way then take a look at some of the hypermedia enabled formats:
Mason: https://github.com/JornWildt/Mason
HAL: https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-07
Siren: https://github.com/kevinswiber/siren
Collection+JSON: http://amundsen.com/media-types/collection/format/
JSON API: http://jsonapi.org/
Hydra: http://www.markus-lanthaler.com/hydra/