Using JArray for serializing data from database in WebAPI (C#) - c#

I want to achieve the following JSON data:
[
{
"name":"Deutschland",
"code":"de"
},
{
"name":"Frankreich",
"code":"fr"
},
{
"name":"Japan",
"code":"jpn"
}
]
Currently I'm getting this result of JSON data:
{
"groups":[
{
"name":"Deutschland",
"code":"de"
},
{
"name":"Frankreich",
"code":"fr"
},
{
"name":"Japan",
"code":"jpn"
}
]
}
Here is the code of the Controller:
public dynamic GetGroups()
{
JObject o = JObject.FromObject(new
{
groups = from g in db.QR_Groups
select new
{
name = g.name,
code = g.code
}
});
return o;
/*Here I've tried to get JSON data as array without the Property "groups"*/
//JArray a = new JArray(
// from g in db.QR_Groups
// select new JValue(g));
//return a;
}
Can anyone tell me how to retrieve the JSON data as per the first JSON example above?
And is the type "dynamic" good practice for the method?

First of all there is no need to do serialization manually. ASP.Net WebApi MediaFormatters are going to take care of it based on the Request Content-Type. So Create a class as shown below.
public class Group
{
public string name { get; set; }
public string code { get; set; }
}
Then your Web API endpoint should be -
[HttpGet]
public HttpResponseMessage GetCountries()
{
List<Group> groups = (from g in db.QR_Groups
select new Group
{
name = g.name,
code = g.code
}).ToList();
return Request.CreateResponse(HttpStatusCode.OK, groups);
}
And when I make a Fiddler request, I was able to get the output which you are interested -

Try this one:
var json = JsonConvert.SerializeObject(from g in db.QR_Groups
select new
{
name = g.name,
code = g.code
});
And is the type "dynamic" good practice for the method?
no, it's not best practise. Better one is to create new class

Related

Filtering nested lists with nullable property

Say I have the following class structures
public class EmailActivity {
public IEnumerable<MemberActivity> Activity { get; set; }
public string EmailAddress { get; set; }
}
public class MemberActivity {
public EmailAction? Action { get; set; }
public string Type { get; set; }
}
public enum EmailAction {
None = 0,
Open = 1,
Click = 2,
Bounce = 3
}
I wish to filter a list of EmailActivity objects based on the presence of a MemberActivity with a non-null EmailAction matching a provided list of EmailAction matches. I want to return just the EmailAddress property as a List<string>.
This is as far as I've got
List<EmailAction> activityTypes; // [ EmailAction.Open, EmailAction.Bounce ]
List<string> activityEmailAddresses =
emailActivity.Where(
member => member.Activity.Where(
activity => activityTypes.Contains(activity.Action)
)
)
.Select(member => member.EmailAddress)
.ToList();
However I get an error message "CS1503 Argument 1: cannot convert from 'EmailAction?' to 'EmailAction'"
If then modify activityTypes to allow null values List<EmailAction?> I get the following "CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type".
The issue is the nested .Where it's returning a list, but the parent .Where requires a bool result. How would I tackle this problem?
I realise I could do with with nested loops however I'm trying to brush up my C# skills!
Using List.Contains is not ideal in terms of performance, HashSet is a better option, also if you want to select the email address as soon as it contains one of the searched actions, you can use Any:
var activityTypes = new HashSet<EmailAction>() { EmailAction.Open, EmailAction.Bounce };
List<string> activityEmailAddresses =
emailActivity.Where(
member => member.Activity.Any(
activity => activity.Action.HasValue &&
activityTypes.Contains(activity.Action.Value)
)
)
.Select(activity => activity.EmailAddress)
.ToList();
You want to use All or Any depends if you want each or at least one match...
HashSet<EmailAction> activityTypes = new HashSet<EmailAction> { EmailAction.None };
var emailActivity = new List<EmailActivity>
{
new EmailActivity { Activity = new List<MemberActivity>{ new MemberActivity { Action = EmailAction.None } }, EmailAddress = "a" },
new EmailActivity { Activity = new List<MemberActivity>{ new MemberActivity { Action = EmailAction.Click } }, EmailAddress = "b" }
};
// Example with Any but All can be used as well
var activityEmailAddresses = emailActivity
.Where(x => x.Activity.Any(_ => _.Action.HasValue && activityTypes.Contains(_.Action.Value)))
.Select(x => x.EmailAddress)
.ToArray();
// Result is [ "a" ]

A generic async method for requesting optionally paginated lists of different resources

I am accessing a REST API which returns a list of resources in JSON format:
{
"products": [
{ ... },
{ ... }
]
}
When the list is big (>50 items) the response becomes paginated and an additional pagination item is added to the root node of returned JSON like that:
{
"pagination": {
"results" : 490,
"page" : 1,
"page_size" : 50,
"pages" : 10
},
"products": [
{ ... },
{ ... }
]
}
In order to cater for that I have a PaginatedList class (probably not the best name) which looks like that:
public class PaginatedList
{
[JsonProperty("pagination")]
public Pagination Pagination { get; set; }
}
a ProductList class that looks like that:
public class ProductList : PaginatedList
{
[JsonProperty("products")]
public List<Product> Products { get; set; }
}
a Pagination class like that:
public class Pagination
{
[JsonProperty("results")]
public int Results { get; set; }
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("page_size")]
public int PageSize { get; set; }
[JsonProperty("pages")]
public int Pages { get; set; }
}
To retrieve my resource I use:
public List<Product> GetProducts()
{
return getResourceAsync<ProductList>(productsResourceName).Result.Products;
}
and:
async Task<T> getResourceListAsync<T>(string resourceName)
{
var url = string.Concat(BaseUrl, resourceName);
var credentials = new NetworkCredential(Username, Password);
var handler = new HttpClientHandler { Credentials = credentials };
using (var client = new HttpClient(handler)) {
var response = await client.GetAsync(url);
var contentString = await response.Content.ReadAsStringAsync();
var resource = await JsonConvert.DeserializeObjectAsync<T>(contentString);
return resource;
}
}
Adding support for pagination inside the GetProducts method would be pretty easy but that would mean duplicating very similar code for every type of resource (products, customers, suppliers, etc). The question is, how do I get the getResourceListAsync method so that it supports paginated and non-paginated lists AND works for different resources?
To make this scenario possible :
// supports both scenarios
var json = #"{ 'products': [ { Id : 1 , Name : 'A' }, { Id : 2 , Name : 'B' } ] }";
var results = Helper.ParseFromJsonResult<Product>(json);
var anotherJson = #"{ 'pagination': {
'results' : 490,
'page' : 1,
'page_size' : 50,
'pages' : 10
},
'products': [
{ Id : 1 , Name : 'A' }, { Id : 2 , Name : 'B' }
]}";
var anotherResults = Helper.ParseFromJsonResult<Product>(anotherJson);
You can use this codes :
public static class Helper
{
private static readonly PluralizationService _NameService =
PluralizationService.CreateService(new CultureInfo("en-us"));
// Provides Plural names [ products for Product ]
// to determinate the name of the result for example products for Product class
private static ModuleBuilder _ModuleBuilder;
static Helper()
{
var asmName = new AssemblyName();
asmName.Name = "MyHelpers";
AssemblyBuilder asmBuilder = Thread.GetDomain().DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
_ModuleBuilder = asmBuilder.DefineDynamicModule("MyHelpers");
// Assembly to put runtime generated classes to that.
}
private static readonly IDictionary<Type, Type> _HelpersCache = new Dictionary<Type, Type>();
public static List<T> ParseFromJsonResult<T>(String json)
{
Type resultType = null;
var entityType = typeof(T);
var pluralName = _NameService.Pluralize(entityType.Name).ToLowerInvariant();
// products for Product class
if (_HelpersCache.ContainsKey(entityType))
{
// better performance
resultType = _HelpersCache[entityType];
}
else
{
// need another runtime generated class
// result :
/* public class products
{
public List<Product> products;
}
*/
TypeBuilder resultTypeBuilder = _ModuleBuilder.DefineType(pluralName, TypeAttributes.Public);
FieldBuilder field = resultTypeBuilder.DefineField(pluralName, typeof(List<T>), FieldAttributes.Public);
resultType = resultTypeBuilder.CreateType();
_HelpersCache.Add(entityType, resultType);
}
Object result = JsonConvert.DeserializeObject(json, resultType);
return (List<T>)resultType.GetField(pluralName).GetValue(result); // get products field value
}
}
I hope this helps, Let me know if you want more information
Good luck
I see your problem. Was stuck in the same one actually. What I ended up doing was an interface that my classes i want to paginte implement. As I did this for export of data it is called IExportable. This thing returns a PagedResult and takes a IPagedRequest.
So the point is that my code in the task is just working with interface and does not actually know what the end type is. PagedResult is a type with generics.
Hope it helps, trying to write this from top of my head without the source.

C# Facebook SDK dynamic data conversion

I got an Object from Facebook SDK
var responsePages = (JsonObject)FBClient_.Get(new { ids =
[123123123, 123123123, 12312213, etc]});
This query returns data (see image)
Now how do I convert this into a list of objects?
I have tried following but it does not work
var pe = (from dynamic page
in (IList<object>)(object)responsePages.Values
orderby page.name ascending
select new FBPage
{
Id = Convert.ToString(page.id),
}
).ToList();
So that failed, would appreciate any help because this dynamic stuff drives me seriously mad.
Thanks
You don't need to cast if you are using dynamic.
var fb = new FacebookClient();
dynamic result = fb.Get(new { ids = new[] { "...", "..." } });
var pages = new List<FBPage>();
foreach (var page in result.Values)
{
var fbPage = new FBPage {
Id = page.id,
Name = page.name
};
pages.Add(fbPage);
}
or if you want to use linq. (extension methods are not supported for dynamic, so you will need to do some casting, JsonObject => IDictionary<string, dyanmic>, JsonArray => IList<dynamic>)
var pages = ((IDictionary<string, dynamic>)result)
.Select(kpv => kpv.Value)
.Select(p => new FBPage { id = p.id, name = p.name })
.ToList();
Or you strongly typed classes.
var fbPages = fb.Get<IDictionary<string, FBPage>>(new {
ids = new[] { "...", "..." }
}).Values;
public class FBPage
{
public string id { get; set; }
public string name { get; set; }
}
'responsePages.Values' is an ICollection<JsonValue>
JsonValues can be serialized to Json strings, which can then be made the play things of a good Json deserializer such as Json.Net.
Using a simple loop this might look something like:
List<dynamic> dynamicList = new List<dynamic>();
List<FBPage> pe = new List<FBPage>();
foreach(var page in responsePages.Values)
{
//ToString is overridden in JsonValue to provide a string in Json format
string pageAsJsonString = page.ToString();
//Deserialize (parse) to a dynamic object using Json.Net's JObject.Parse static method
dynamic parsedPage = JObject.Parse(pageAsJsonString);
dynamicList.Add(parsedPage);
//Alternatively, if you have an appropriate object handy, deserialize directly:
FBPage deserializedPage = JsonConvert.DeserializeObject<FBPage>(pageAsJsonString);
pe.Add(deserializedPage);
}
foreach(dynamic page in dynamicList)
{
Console.WriteLine(page.name);
}
foreach(FBPage page in pe)
{
Console.WriteLine(page.Id);
}

Linq using StartsWith always empty

I have a simple List with dummy data as follows:
List<Organisation> list = new List<Organisation>();
list.Add(new Organisation() { LogoUrl = "/images/logos/Blade.png", OrganisationId = 1, OrganisationName = "Blade" });
list.Add(new Organisation() { LogoUrl = "/images/logos/Torn.png", OrganisationId = 2, OrganisationName = "Torn" });
When I run the linq query:
var results = from org in OrganisationsController.GetDummyList()
where org.OrganisationName.StartsWith(searchString)
select org;
It always returns an Empty result. In this case the searchString is specified by the user and the example would be "Tor".
Using different variations like 'where org.OrganisationName == searchString' where the search string is Torn works. But StartsWith never works.
Any ideas where I'm going wrong?
EDIT:
From Jon's code I changed my code to look as follows:
public JsonResult Search(string searchString)
{
//create json result object
JsonResult data = new JsonResult();
var list = OrganisationsController.GetDummyList();
//query the list
var results = from org in list
where org.OrganisationName.ToLower().Contains(searchString.ToLower())
select org;
if (results.Any())
{
System.Diagnostics.Debug.Write("found");
}
//setup the data
data.Data = results;
//return the data
return Json(data, JsonRequestBehavior.AllowGet);
}
Note: I changed the StartsWith to Contains, but both are giving me similary problems.
One of my organisations is called 'Absa'. Here's the really strange thing when I fire up the app for the first time putting in 'bsa' returns nothing, I then enter 'Absa' and it returns a good result. Then I entered 'bsa' again just to double check and it returned Absa which it didn't in the first test. Why would the result not work at first then work later?
Thanks,
Jacques
Unable to reproduce. It works fine for me:
using System;
using System.Collections.Generic;
using System.Linq;
class Organisation
{
public string LogoUrl { get; set; }
// Removed redundant Organisation prefixes
public int Id { get; set; }
public string Name { get; set; }
}
class Test
{
static void Main()
{
// Used collection initializer for sanity
var list = new List<Organisation>
{
new Organisation { LogoUrl = "Blade.png", Id = 1, Name = "Blade" },
new Organisation { LogoUrl = "Torn.png", Id = 2, Name = "Torn" },
};
string searchString = "Tor";
var query = from org in list
where org.Name.StartsWith(searchString)
select org;
// Nicer version:
// var query = list.Where(org => org.Name.StartsWith(searchString));
Console.WriteLine(query.Count()); // 1
}
}
Work out the difference between your code and my code to find out what's wrong.
In particular, you've shown code using List<T>, which means LINQ to Objects. If your real code uses LINQ to SQL or Entity Framework, that could easily affect things.

Json serialization in asp.net mvc c#

public ActionResult About()
{
List listStores = new List();
listStores = this.GetResults(“param”);
return Json(listStores, “Stores”, JsonRequestBehavior.AllowGet);
}
Using the above code I am able to get the below result :
[{"id":"1","name":"Store1","cust_name":"custname1","telephone":"1233455555",
"email":"abc#ac.com","geo":{"latitude":"12.9876","longitude":"122.376237"}},
{"id":"2","name":"Store2","cust_name":"custname2","telephone":"1556454",
"email":"nfnf#ac.com","geo":{"latitude":"12.9876","longitude":"122.376237"}},
how would I able to get the result in below format? Would need stores at the beginning of the result.
{
"stores" : [
{"id":"1","name":"Store1","cust_name":"custname1","telephone":"1233455555",
"email":"abc#ac.com",
"geo":{"latitude":"12.9876","longitude":"122.376237"}},
{"id":"2","name":"Store2","cust_name":"custname2","telephone":"1556454",
"email":"nfnf#ac.com","geo":{"latitude":"12.9876","longitude":"122.376237"
}} ] }
Try
return Json(new { stores = listStores }, JsonRequestBehavior.AllowGet);
In the above statement, you're creating a new object with a property named "stores", which is then populated with the array of items from the list.
You could also use a class, something defined like so:
[DataContract]
public class StoreListJsonDTO
{
[DataMember(Name = "stores")]
public List Stores { get; set; }
public StoreListJsonDTO(List storeList)
{
this.Stores = storeList;
}
}
Then in your code, you'd do:
var result = new StoreListJsonDTO(listStores);
return Json(result, JsonRequestBehavior.AllowGet);

Categories