How to serialize an IList<T>? - c#

I've got an OR mapper (iBatis.Net) that returns an IList.
// IList<T> QueryForList<T>(string statementName, object parameterObject);
var data = mapper.QueryForList<Something>(statement, parameters);
I'm trying to use it in an webservice an want to return the data 1:1. Of course I can't return IList in a WebMethod, because it is an interface and therefore not serializable.
I found that the mapper is really returning an List. But I'm afraid to cast it to List because of course the mappers inner workings could change in future versions (and it just feels dirty).
So should I ...
a) return new List<Something>(data);
b) return (List<Something>)data;
c) // your solution here
Thanks a lot!

If it really is a List<T> but you want to protect against change and have it still work, then the most performant solution will be to attempt to cast it to a list, and if that fails then create a new list from its content, e.g.
var data = mapper.QueryForList<T>(statement, parameters);
var list = data as List<T> ?? new List<T>(data);
However, you mention that you can't return an interface because it's a web service. This may have been true with ASMX and the XmlSerializer class, but if you build the web service using WCF and use the DataContractSerializer then it will happily serialize collection interfaces (both as inputs to and outputs from the service). That type of change may be somewhat larger than you're looking for though!

Why should you serialize IList :) Just use it as a source for your own collection and serialize it:
var data = mapper.QueryForList<T>(statement, parameters);
var yourList = new List<T>(data);
//Serialize yourList here ))

I don't think you need a c).
It should be pretty safe to use solution a).
This solution depends on the public api of IBatis.net. Good api's don't change their public api unless it's really the only solution to a mission critical problem
Hope this helps.

Related

Is it good practice to return anonymous type in respond to HTTP GET request?

My Web API where one of GET endpoint return collection of ProductsByCategory.
public async Task<ActionResult<IEnumerable<ProductsByCategory>>> GetProductsByCategories()
{
var productsByCategories = await northwindContext.Categories.Select(category => new ProductsByCategory
{
CategoryName = category.CategoryName,
ProductCount = category.Products.Count
}
).ToListAsync();
return productsByCategories;
}
But I know that JSON and even XML don`t need in name of the type. They just need in name of the property and its value. So I have another way how to implement this method(using anonymous types):
public async Task<ActionResult<IEnumerable>> GetProductsByCategories()
{
var productsByCategories = await northwindContext.Categories.Select(category => new
{
CategoryName = category.CategoryName,
ProductCount = category.Products.Count
}
).ToListAsync();
return productsByCategories;
}
I liked second approach because I don't need in writing code of such types like ProductsByCategory and seems to me more logical since JSON(XML) don't need in type's name I don't need to create not anonymous type. But this is all my thoughts and I am pretty new in field of ASP .NET Core and it is possible that I miss some parts and my guesses are wrong. So is it good practise to pass collection of anonymous types as respond to HTTP GET request or is it better to specify what type of items is collection keeps?
You right, you will have the same resulting serialized object (xml, json), and you can use anonymous type. But you should keep in mind:
When your explicitly define resulting class, your code will be
cleaner
For explicitly defined resulting class your may define some validation
rules using attributes for serializer
If you use documentation tools, for example swagger, you also may use attributes to provide additional documentation.
Api should not be ambiguous.
Everything depends on your preferences. If you want use anonymous type, you may.

OData dynamic template class

I am working with OData V3, and i came across this line:
var people = await client.For<People>().FindEntriesAsync();
In order for this to work, I need to define the People class, which has a bunch of set/get, which represent the fields I want.
Is there a simple and convenient way to avoid hard coding the structure classes? I want to be able to issue that command without having to define a specific "People" class. I would much rather have my results be in dictionary form, were the key's would be the column name, and the value would be the value in that column for the specific object.
Simple.OData.Client supports untyped scenarios, in which the CLR class is unnecessary.
For example:
var people = await client.For("People").FindEntriesAsync();
Then, people is a dictionary instance that you can use IDictionary<string, object> to refer. Thanks.
I don't think there is a way to avoid define a class like People, but if you really want to do this, you can try un-typed feature in OData.
Simple.OData.Client supports typed, untyped and dynamic scenario. So you can rewrite your query like this:
var x = ODataDynamic.Expression;
var people = await client.For(x.People).FindEntriesAsync();
here is another example:
var person = await client
.For(x.People)
.Filter(x.FirstName == "John")
.Select(x.LastName)
.FindEntryAsync();

MVC3 - Modifying object before serializing to JSON

I'm currently developing a small REST API for my application. It works fine. There's one problem, though. The results returned to the user contain too much data. My controller looks like this:
public JsonResult Profile(string name)
{
var encodedName = HttpUtility.HtmlEncode(name);
var n = encodedName.Replace('+', ' ');
var profile = profileSource.GetProfileForName(n);
if (profile == null)
{
HttpContext.Response.StatusCode = 404;
}
// XXXXX: how to remove certain fields from the profile?
return Json(profile, JsonRequestBehavior.AllowGet);
}
Any idea what's the cleanest way to deal with this? Is there some way to annotate the profile model so that certain fields won't get serialized? I guess alternatively I could construct a custom Model for this specific case or hack that JsonResult somehow. Either of these ways adds some extra overhead, though.
You can use the LINQ select method to project into an anonymous type.
You should probably do a custom object with a subset of ProfileĀ“s properties. Then translate the original object to the new DTO like object. (Tip:Try AutoMapper). Serialize and return.
return Json(new{profile.FirstName, profile.LastName, profile.OtherFields}, JsonRequestBehavior.AllowGet);
I ended up using inheritance. Basically I have a "shared" model (base class) and one that derives that and adds some extra fields to it. At the source I simply construct a shared instance for my REST API while the other part of the app uses the derived one. Pretty simple and seems to work well.

Serializing encapsulated lists in a Web Service

I have a class MyClass containing a private List<MySecondClass> myList. The list is exposed through a getter as follows:
public IEnumerable<MySecondClass> MyList
{
get { return myList.Select(a => a); }
}
The list is modified through public AddItem(MySecondClass itemToAdd) and ClearItems() methods. I believe that this is a properly encapsulated list.
The problem lies in that I need to pass an object of type MyClass (containing myList) via SOAP to a web service, which fills myList (using the AddItem() method), and then returns the object.
However, when the webmethod returns the class, after serialization myList is empty. I am suspecting this is because I do not have a setter for myList, which is causing the list not to be set during serialization.
Is this a good assumption, or am I way off? If the problem is what I think it is, is there a way to allow for the list to be successfully passed from the webmethod without breaking encapsulation (I do not want to expose a generic list)?
Without trying this directly myself, I believe that you could definitely be correct.
serialization in .NET makes utilizing read only properties a fun circus.because the .net default serialization process requires a setter property in order to "deserialize" the object. Without a setter property the serialization piece will still work allowing you to serialize to a drive or across the network. But, it is the deserialization process that will fail which could definitely be why your collection is empty. Im just amazed it doesn't error out to be honest.
Have you tried to add a simple setter just to verify that this is in fact the issue just so that we know with 100% certainty that this is the problem before working to solve it.
While I never really solved the initial problem, what I did do to get it working was simplify the data that was being passed to the web method. Instead of passing an entire object to the web method, I instead passed a unique identifier. The webmethod then returns the list I need, and I handle actually adding the items in this list to the object client-side.
The XML Serializer used by ASMX services only serializes public read/write properties.

Don't want to JSON serialize the whole list of classes

I've got a IList of Sites in my application and Site has a large amount of properties.
I'm wanting to convert this list to JSON to be used in a dropdownlist similar to this
var sites = SiteRepository.FindAllSites();
return new JsonResult() { Data = sites, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
the problem I have is that I only want to use the id and name properties of the site class. I was thinking a way round this would be to use an 'adaptor' class that would then only expose these two properties and I would then serialize that.
The problem I have is I want to make the class generic so that it can handle any list of objects. Has anybody come across a similar situation and solved it?
EDIT: I can't use the [ScriptIgnore] Attribute as there may be a case when I do want to serialize the whole class.
Can you create an anonymous class from your list of sites?
var sites = SiteRepository.FindAllSites().Select(x=> new { Id=x.Id, Name=x.Name});
Since FindAllSites() seems to return an IList, which is descended from IEnumberable, you should be able to use System.Linq's extension methods (i.e. Select() ). That'll transform the List<Site> (with all the properties) to IEnumerable<some_anon_class> (with only 2 properties) which is then given to that JsonResult thing instead of the list of Site.
If you decorate you class fields with [ScriptIgnore] (System.Web.Script.Serialization) C# will ignore them during serialization using Json in much the same way that decorating with [XmlIgnore] would for Xml serialization.
MSDN

Categories

Resources