MVC API: Structuring XML Response with child elements - c#

Very new to MVC. I am currently writing an API and have a strict format that I need the XML to be returned in.
At the moment, I am using my EntityModel to expose my SQL Stored procedure. I have then created an Complex Type for the SP.
I have a controller that is calling the SP and the results are returned in XML.
This is fine however, the output is currently (for example):
<product>
<productId>12345</productId>
<inStock>True</inStock>
<shelfLevel>10</shelfLevel>
<onOrder>0</onOrder>
<height>10</height>
<width>15</width>
<depth>12</depth>
<colour>green</colour>
</product>
However, it needs to be structured as:
<product>
<productId>12345</productId>
<availability>
<inStock>True</inStock>
<shelfLevel>10</shelfLevel>
<onOrder>0</onOrder>
</availability>
<dimensions>
<height>10</height>
<width>15</width>
<depth>12</depth>
</dimensions>
<colour>green</colour>
</product>
I can not see any way of including the 'availabilty' and 'dimensions' wrapper elements using my current approach of EntityModel and Complex Type combination.
Below is my code from the controller for the existing output:
// GET api/product/5
//ProductAvailability_Result is the Complex Type derived from the SP output columns
public IEnumerable<ProductAvailability_Result> Get(int id)
{
myDB_DevEntities db = new myDB_DevEntities();
//ProductAvailability is a SP consisting of a simple 'select' statement that returns the resultset
var Result = db.ProductAvailability(id);
return Result.ToList();
}
Can anyone give any pointers on how to achieve this? Am i approaching this on completly the wrong way by trying to use the above method i.e. should I be ditching EntityModel? It works great until I need to change the structure.
Any advice would be much appreciated.

You could create a DTO (data transfer object) that looks like way you'd like, but you'd have to do a little bit of data transformation. You'd start with defining the class structure that matches the structure of the expected XML:
[XmlRoot("product")]
public class ProductDto
{
[XmlElement("productId")]
public int ProductId { get; set; }
[XmlElement("availability")]
public AvailabilityDto Availability { get; set; }
...
}
[XmlRoot("availability")]
public class AvailabilityDto
{
[XmlElement("inStock")]
public bool InStock { get; set; }
...
}
And then in your API method you can transform your DAO (data access object) into your DTO before you return it to the client:
public ProductDto GetProductAvailability(id)
{
var result = db.ProductAvailability(id);
return new ProductDto
{
ProductId = result.productId,
Availability = new AvailabilityDto
{
InStock = result.inStock,
...
},
...
}
}
Obviously this could amount to a ton of work, so I too am curious what other answers to your question may pop up.

Related

How to convert an IHttpActionResult (with JSON inside) to an object I can process with LINQ

It might be a noob question or an architectural misunderstanding, but I ask it anyhow because I am out of ideas and search terms: The goal is to implement a controller CountriesController() which is supposed to concatenate the (JSONish) results of two endpoints.
Assume I have two endpoints api/allowedCountriesToSell and api/allowedCountriesToBuy which are implemented as CountriesSellController() and CountriesBuyController() respectively. Both of them give back data as JSON which I want to merge and offer as a new endpoint. I am aware that this architecture is not ideal, but I am not allowed to do it architecturally different. Furthermore, I actually have to POST two different files to those endpoints - both existing controllers contain something like
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase file, string selectBox)
{ // ...
My new endpoint compiles all these two required parameters, let's call them myFileX, and mySelectBox. Here what I have have so far:
var myOtherContoller1 = new CountriesSellController();
var list1 = myOtherContoller1.FileUpload(myFile1,mySelectBox);
var myOtherContoller2 = new CountriesSellController();
var list2 = myOtherContoller1.FileUpload(myFile2,mySelectBox);
my result = list1.asEnumerable().Concat(list2.asEnumerable()); // Pseudocode. Here I am lost.
return Ok(result);
The problem is that both list1 and list2 are of type IHttpActionResult and I am not sure how to extract the data inside that. Ideally, result would be of type IEnumerable<UploadStatusDto> where I define the respective data transfer object as
namespace API.Models
{
public class UploadStatusDto
{
public int UploadId { get; set; } // contained in the response of both controllers
public string FileName { get; set; } // myFileX - parameter for calling the 2 existing controllers
public int UploadStatus { get; set; } // coming back within listX
public int Type { get; set; } // whether it is a buy or a sell, i.e. which controller I called
}
Any guidance is appreciated.
You need to do something line this.
var response = await myOtherContoller1.FileUpload(myFile2,mySelectBox).ExecuteAsync();
This will return HttpResponseMessage and you can get the content from it
You can get your content like this: Getting content/message from HttpResponseMessage.
My suggestion though, would be to extract the logic of your other controllers to a service class, and call both in this and the other two, the logic that is now in the original controllers.

Adding conditions on complex properties with ServiceStack AutoQuery

I need to add filtering to my API requests that support AutoQuery, so based on this SO answer, used q.And to add conditions. The issue is that one of the POCO properties is a List<string> and it seems doing a simple Contains() won't work. Here's a simple example of what I have:
public class PocoObject
{
public int Id { get; set; }
public List<string> Names { get; set; }
}
My service looks like this:
public object Get(PocoObjects request)
{
var q = AutoQuery.CreateQuery(request, Request.GetRequestParams());
if (someCondition)
{
q.And(x => x.Names.Contains(request.TargetName));
}
return AutoQuery.Execute(request, q);
}
Problem is, I get an error like this:
variable 'x' of type 'TestProject.ServiceModel.Types.PocoObject' referenced from scope '', but it is not defined
If I change the Contains to a simpler equality comparison on another property, the AutoQuery works. Any ideas how to accomplish this?
You can't do a server side SQL query on a blobbed complex type property like List<string>. Any queries need to be applied on the client after the results are returned from the db and its deserialised back into a typed POCO.

ResponstDTO with complex Property in ServiceStack

Havin a Response with a complex property, i want to to map to my responseDTO properly. For all basic types it works out flawlessly.
The ResponseDTO looks like this:
public class ResponseDto
{
public string Id {
get;
set;
}
public struct Refs
{
public Genre GenreDto {
get;
set;
}
public Location LocationDto {
get;
set;
}
}
public Refs References {
get;
set;
}
}
Genre and Location are both for now simple classes with simple properties (int/string)
public class GenreDto {
public string Id {
get;
set;
}
public string Name {
get;
set;
}
}
Question:
Is there any way, without changing/replacing the generic unserializer ( and more specific example) (in this example JSON ) to map such complex properties?
One specific difference to the GithubResponse example is, that i cant use a dictionry of one type, since i have different types under references. Thats why i use a struct, but this seems not to work. Maybe only IEnumerable are allowed?
Update
There is a way using lamda expressins to parse the json manually github.com/ServiceStack/ServiceStack.Text/blob/master/tests/ServiceStack.Text.Tests/UseCases/CentroidTests.cs#L136 but i would really like to avoid this, since the ResponseDTO becomes kinda useless this way - since when writing this kind of manual mapping i would no longer us Automapper to map from ResponseDto to DomainModel - i though like this abstraction and "seperation".
Thanks
I used lambda expressions to solve this issue, a more complex example would be
static public Func<JsonObject,Cart> fromJson = cart => new Cart(new CartDto {
Id = cart.Get<string>("id"),
SelectedDeliveryId = cart.Get<string>("selectedDeliveryId"),
SelectedPaymentId = cart.Get<string>("selectedPaymentId"),
Amount = cart.Get<float>("selectedPaymentId"),
AddressBilling = cart.Object("references").ArrayObjects("address_billing").FirstOrDefault().ConvertTo(AddressDto.fromJson),
AddressDelivery = cart.Object("references").ArrayObjects("address_delivery").FirstOrDefault().ConvertTo(AddressDto.fromJson),
AvailableShippingTypes = cart.Object("references").ArrayObjects("delivery").ConvertAll(ShippingTypeDto.fromJson),
AvailablePaypmentTypes = cart.Object("references").ArrayObjects("payment").ConvertAll(PaymentOptionDto.fromJson),
Tickets = cart.Object("references").ArrayObjects("ticket").ConvertAll(TicketDto.fromJson)
});
So this lamda exprpession is used to parse the JsonObject response of the request and map everything inside, even nested ressources. This works out very well and flexible
Some time ago i stumbled upon a similar problem. Actually ServiceStack works well with complex properties. The problem in my scenario was that i was fetching data from a database and was passing the objects returned from the DB provider directly to ServiceStack. The solution was to either create DTOs out of the models returned by the DB provider or invoke .ToList() on those same models.
I'm just sharing some experience with SS but may be you can specify what's not working for you. Is there an exception thrown or something else.

Best way to consume xml feed in asp.net MVC (c#)

I have an MVC website that, when you click a button, will use Get method to grab xml data from another website. I need to then display part of this XML in my webpage.
My current approach is to deserialize the XML into objects, and pass the objects into the View, which will then grab the appropriate data.
My problem is that my classes don't match the XML data entirely (it doesn't have every element/attribute/etc). The data is too long, with too many elements and attributes, so I don't want to write everything to the classes. And I couldn't create classes from the XML data using XSD.exe because of some error in the data (though the xml data works fine when my webpage is reading it).
Is there a more efficient way of doing this?
Read in this link that IXmlSerializable might be away, although the comments also noted some problems with it. And it seems like it might be quite complicated.
How to deserialize only part of an XML document in C#
Your help is much appreciated. Thanks!
Use framework to consume Atom feeds. See the following: System.ServiceModel.Syndication namespace - msdn.microsoft.com/en-us/library/system.servicemodel.syndication.aspx
Instead of directly deserializing the atom feed xml into objects first load the xml into the XDocument object and then query the XDocument object using XLinq and create the necessary ViewModel that need to be passed to the view.
For ex.
View Model
public class FeedViewModel
{
..
public FeedItem[] FeedItems { get; set; }
}
public class FeedItem
{
public string Title { get; set; }
public string Description { get; set; }
public DateTime Date { get; set; }
}
In your action
var feedDocument = XDocument.Load(feedUrl);
var feedItems = feedDocument.Descendants("item")
orderby DateTime.Parse(feed.Element("pubDate").Value) descending
select new FeedItem
{
Title = feed.Element("title").Value,
Description = feed.Element("description").Value,
Date = DateTime.Parse(feed.Element("pubDate").Value)
}.ToArray();
return View(new FeedViewModel{ FeedItems = feedItems });
http://deepumi.wordpress.com/2010/02/21/how-to-consume-an-atom-rss-feed-using-asp-net-c-with-linq/

C# + Querying XML with LINQ

I'm learning to use LINQ. I have seen some videos online that have really impressed me. In an effort to learn LINQ myself, I decided to try to write a query to the NOAA web service. If you put "http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?zipCodeList=20001&format=24+hourly&startDate=2010-06-10&numDays=5" in your browser's address bar, you will see some XML. I have successfully retrieved that XML in a C# program. I am loading the XML into a LINQable entity by doing the following:
string xml = QueryWeatherService();
XDocument weather = XDocument.Parse(xml);
I have a class called DailyForecast defined as follows:
public class DailyForecast
{
public float HighTemperature { get; set; }
public float LowTemperature { get; set; }
public float PrecipitationPossibility { get; set; }
public string WeatherSummary { get; set; }
}
I'm trying write a LINQ query that adheres to the structure of my DailyForecast class. At this time, I've only gotten to this far:
var results = from day in response.Descendants("parameters")
select day;
Not very far I know. Because of the structure of the XML returned, I'm not sure it is possible to solely use a LINQ query. I think the only way to do this is via a loop and traverse the XML. I'm seeking someone to correct me if I'm wrong. Can someone please tell me if I can get results using purely LINQ that adhere to the structure of the DailyForecast class? If so, how?
Thank you!
Since your xml may return multiple records,
var results = from day in response.Descendants("parameters")
select new DailyForecast()
{
HighTemperature = day.Element("param name corresponding to high temp"),
};
return result.ToList(); //or any type of collection you want to return

Categories

Resources