Hi i have a C# model class. This class i need to pass as json response by setting his property . one property name Product of this class have type of another product class, when there is no data for Product i am getting all inner property value as blank but instead of that i want blank json property .
For Exp My Class is
public class Profile_BO
{
public int Id { get; set; }
public string Username { get; set; }
public Product product{ get; set; }
public class Product
{
public int Id { get; set; }
public string Type { get; set; }
}
}
i am initializing this class from C# data table like below : -
Profile_BO profile_BO = new Profile_BO();
foreach (DataRow dr in result.Tables[0].Rows)
{
profile_BO.Id = Convert.ToInt32(dr[0]);
profile_BO.Username = Convert.ToString(dr[1]);
}
Product product = new Product();
foreach (DataRow dr1 in result.Tables[1].Rows)
{
product.Id = Convert.ToInt32(dr1[0]);
product.Type = Convert.ToString(dr1[1]);
}
profile_BO.product = product;
Finally when i am passing as a response to method : -
public async Task<HttpResponseMessage> GetUserInfo(Profile_Request profile_Request)
{
return request.CreateResponse(HttpStatusCode.OK, profile_BO);
}
And when calling on client side i am getting response json if data is present in table like : -
{
"Id": "1",
"Username": "abc",
"product": {
"Id": "232",
"Type": "34cvdcbv"
}
}
But when i have no data in product table i am getting below : -
{
"Id": "1",
"Username": "abc",
"product": {
"Id": 0,
"Type": ""
}
}
But if no data i want output like below : -
{
"Id": "1",
"Username": "abc",
"product": {}
}
One other question is : - Is it right way for binding response model from dataset ?
the problem you are facing, is that you are initializing an instance of Product regardless of the fact, that there might be no product at all. this results, to its properties getting initialized with default values. Int32 defaults to 0. System.String as a reference type is null.
Profile_BO profile_BO = new Profile_BO();
foreach (DataRow dr in result.Tables[0].Rows)
{
profile_BO.Id = Convert.ToInt32(dr[0]);
profile_BO.Username = Convert.ToString(dr[1]);
}
//I am assuming you only expect one row, since oyur model uses a single Product
//and no collection of products. No need for a loop then.
if(result.Tables[1].Rows.Count == 1) {
Product product = new Product();
var dr1 = result.Tables[1].Rows[0];
product.Id = Convert.ToInt32(dr1[0]);
product.Type = Convert.ToString(dr1[1]);
profile_BO.product = product;
}
This should result in the following JSON being returned:
{
"Id": "1",
"Username": "abc",
"product": null
}
EDIT: If you really must have product : {}, then you need ot change your model.
public class Profile_BO
{
public int Id { get; set; }
public string Username { get; set; }
public object product { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
Declare product as an object. Since all classes inherit from object, you can instantiate it as an object or Product, depending on your case:
if(result.Tables[1].Rows.Count == 1) {
Product product = new Product();
var dr1 = result.Tables[1].Rows[0];
product.Id = Convert.ToInt32(dr1[0]);
product.Type = Convert.ToString(dr1[1]);
profile_BO.product = product;
}
Or:
if(result.Tables[1].Rows.Count == 0) {
var product = new object();
profile_BO.product = product;
}
This will then result in:
{"Id":1,"Username":"Foo Bar","product":{}}
However I strongly advise to go with the first approach, because this will make testing and modifications easier, since you keep your strongly typed approach.
My previous answer doesn't contribute to your final question. So here is my edited solution.
A Better Solution
May be better solution is using Custom Message Handler.
A delegating handler can also skip the inner handler and directly
create the response.
Custom Message Handler:
public class NullJsonHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var updatedResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = null
};
var response = await base.SendAsync(request, cancellationToken);
if (response.Content == null)
{
response.Content = new StringContent("{}");
}
else if (response.Content is ObjectContent)
{
var contents = await response.Content.ReadAsStringAsync();
if (contents.Contains("null"))
{
contents = contents.Replace("null", "{}");
}
updatedResponse.Content = new StringContent(contents,Encoding.UTF8,"application/json");
}
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(updatedResponse);
return await tsc.Task;
}
}
Register the Handler:
In Global.asax file inside Application_Start() method register your Handler by adding below code.
GlobalConfiguration.Configuration.MessageHandlers.Add(new NullJsonHandler());
Now all the Asp.NET Web API Response which contains null will be replaced with empty Json body {}.
References:
1.
2.
Related
I'm trying to allow my entities to be ordered by the Last-Modified property in their metadata, using OData query options.
I tried using a transformer as described in Converting to JSON and accessing metadata, but when I apply ODataQueryOptions to the resulting IQueryable, I get an empty array.
The model and view-model:
public class Foo
{
public int Id { get; set; }
}
public class FooViewModel
{
public string Id { get; set; }
public DateTime LastModified { get; set; }
}
The transformer:
public class Foos_WithLastModified : AbstractTransformerCreationTask<Foo>
{
public Foos_WithLastModified()
{
TransformResults = foos => from foo in foos
let metadata = MetadataFor(foo)
select new
{
Id = foo.Id.ToString(CultureInfo.InvariantCulture),
LastModified = metadata.Value<DateTime>("Last-Modified")
};
}
}
The relevant method in FooController (_session is an IAsyncDocumentSession):
public async Task<ICollection<FooViewModel>> Get(ODataQueryOptions<FooViewModel> options)
{
var settings = new ODataValidationSettings();
settings.AllowedOrderByProperties.Add("LastModified");
options.Validate(settings);
var foos = _session.Query<Foo>()
.TransformWith<Foos_WithLastModified, FooViewModel>();
var odataFoos = (IQueryable<FooViewModel>)options.ApplyTo(foos);
return await odataFoos.ToListAsync();
}
When I hit /api/Foo, the results are as expected:
[
{
"Id": "foos/456",
"LastModified": "2015-11-23T08:43:10.913662Z"
},
{
"Id": "foos/123",
"LastModified": "2015-11-23T08:50:34.0907996Z"
}
]
But when I add OData query options (/api/Foo?$orderby=LastModified), I get an empty array: [].
I also tried changing _session to an IDocumentSession and modifying Get as follows,
[EnableQuery(AllowedOrderByProperties = "LastModified")]
public IQueryable<FooViewModel> Get()
{
return _session.Query<Foo>()
.TransformWith<Foos_WithLastModified, FooViewModel>();
}
but I get the same results.
Are transformers the wrong approach? How can I sort by Last-Modified using OData query options?
I do not know how to handle the OData stuff, never tried that, but in order to query for entities, ordered by the metadata value "Last-Modified" using only RavenDB techniques you can do the following:
Create an index for your entity (in my example a Customer). In this index we add the field LastModified that's using the document's metadata value for Last-Modified.
public class Customer_ByLastModified : AbstractIndexCreationTask<Customer>
{
public class QueryModel
{
public DateTime LastModified { get; set; }
}
public Customer_ByLastModified()
{
Map = customers => from customer in customers
select new
{
LastModified = this.MetadataFor(customer).Value<DateTime>("Last-Modified")
};
}
}
The QueryModel isn't mandatory, but it makes querying via the client API easier, imo. You can then add a Transformer to be able to use the metadata value in your return model:
public class Customers_WithLastModified : AbstractTransformerCreationTask<Customer>
{
public Customers_WithLastModified()
{
TransformResults = results => from customer in results
select new CustomerViewModel
{
Id = customer.Id,
Name = customer.Name,
LastModified = MetadataFor(customer).Value<DateTime>("Last-Modified")
};
}
}
And then query it like this:
using (var session = documentStore.OpenSession())
{
var customers = session.Query<Customer_ByLastModified.QueryModel, Customer_ByLastModified>()
.OrderByDescending(x => x.LastModified)
.TransformWith<Customers_WithLastModified, CustomerViewModel>()
.ToList();
}
Hope this helps!
I have a model class like so (generated from EF):
public partial class Point
{
public int Id { get; set; }
public int First { get; set; }
public int Second { get; set; }
public int Total { get; set; }
}
and a Post method (which is called from Angular) in my controller (ApiController) like so:
[ResponseType(typeof(Point))]
public IHttpActionResult PostPoint(Point points)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
points.Total = points.First + points.Second;
db.ScoreBoard.Add(points);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = points.Id }, points);
}
This will return the whole points object and my POST call will have a Response with all the properties of that object.
Now what I want to do is to return only the Total property and so I tried to changed the return of the PostPoint to :
return CreatedAtRoute("DefaultApi", new { id = points.Id }, points.Total);
Doing this however will return an empty Response to the POST call from Angular.
The Angular post-method looks like this:
this.post = function (Point) {
var request = $http({
method: "post",
url: "/api/PointsAPI",
data: JSON.stringify(Point)
});
return request;
}
How would I go about only returning the Total property of the pointsobject?
It will be empty because you are returning a primitive data type. Your Total property is just a number so when angular parses the response it expects an object and all it sees is "2" (if your Total was 2). So, wrap it in an object and angular will be able to parse it.
return CreatedAtRoute("DefaultApi", new { id = points.Id }, new { points.Total });
This will return { "Total" : 2 } in your body. Now angular will have an object with a Total property.
Hello I'm trying to make a simple online magazine and I got to the part where when the user clicks addtoCart button
My model Cart holds two properties - product and Quantity
public class Cart
{
public ProductLanguages Product { get; set; }
public int Quantity { get; set; }
}
So in my basketViewModel (class) inside my AddProductToCart method I add the product, the details for which I get from database in property of List.
So I can't figure out this issue: Somewhere in the control I should save this list in a Session and if the user adds more products the next time I should get the list from this session. If someone can give me an example of controler with an index action that can do this I would be really thankful.
public class BasketViewModel
{
private readonly IProductLanguagesRepository prodlanRepository;
public List<Cart> listProductsinBasket { get; set; }
public BasketViewModel() : this(new ProductLanguagesRepository())
{
}
public BasketViewModel(IProductLanguagesRepository prodlanRepository)
{
this.prodlanRepository = prodlanRepository;
}
public void AddProductToCart(int id,int quantity)
{
ProductLanguages nwProduct = prodlanRepository.GetProductDetails(id);
if (nwProduct != null)
{
Cart cr = new Cart();
cr.Product = nwProduct;
cr.Quantity = quantity;
listProductsinBasket.Add(cr);
}
Store:
HttpContext.Session["list"] = new List<object> { new object(), new object() };
Retrieve:
var list = HttpContext.Current.Session["list"] as List<object>;
When using Json.NET to serialize a MVC view model to json, I have a generic object property on my view model (public object Result { get; set;}) that is getting serialized to key-value pairs instead of an actual json object. Is there a converter I can use to force it to be serialized properly?
This is what is currently being output by Json.NET:
"result": [
{
"key": "AssetId",
"value": "b8d8fb71-2553-485b-91bf-14c6c563d78b"
},
{
"key": "SearchResultType",
"value": "Assets"
},
{
"key": "Name",
"value": "abstract-q-c-1920-1920-8"
}
]
Instead, I would want it to output this:
"result": {
"AssetId": "b8d8fb71-2553-485b-91bf-14c6c563d78b",
"SearchResultType": "Assets",
"Name": "abstract-q-c-1920-1920-8"
}
EDIT:
To answer the question of how that property is getting populated, it is via a RavenDB index:
public class SiteSearchIndexTask : AbstractMultiMapIndexCreationTask<SiteSearchResult>
{
public class Result
{
public object[] Content { get; set; }
}
public override string IndexName
{
get
{
return "SiteSearch/All";
}
}
public SiteSearchIndexTask()
{
AddMap<Asset>(items => from item in items
where item.IsDeleted == false
select new
{
Id = item.Id.ToString(),
ObjectId = item.Id,
ResultType = SearchResultType.Assets,
Title = item.Name.Boost(3),
Tags = item.Tags.Select(x => x.Name).Boost(2),
Result = (object)item,
Query = string.Join(" ", item.Description)
});
AddMap<User>(items => from item in items
where item.IsDeleted == false
select new
{
Id = item.Id,
ObjectId = item.UserId,
ResultType = SearchResultType.Users,
Title = item.Username.Boost(3),
Tags = (BoostedValue) null,
Result = (object)item,
Query = string.Join(" ", item.FullName, item.Email)
});
Store(x => x.ObjectId, FieldStorage.Yes);
Store(x => x.ResultType, FieldStorage.Yes);
Store(x => x.Title, FieldStorage.Yes);
Store(x => x.Tags, FieldStorage.Yes);
Store(x => x.Result, FieldStorage.Yes);
Store(x => x.Query, FieldStorage.Yes);
}
}
Edit 2
Here are the Asset and User models (truncated for brevity, since they're just a bunch of auto properties)
public class Asset : IHasId
{
public string Id { get; set; }
public Guid AssetId
{
get
{
Guid assetId;
Guid.TryParse((Id ?? string.Empty).Replace("assets/", ""), out assetId);
return assetId;
}
set { Id = "assets/" + value; }
}
public string Name { get; set; }
public string Description { get; set; }
}
public class User : IHasId
{
public User()
{
Status = UserStatus.Active;
}
public string Id { get; set; }
public int UserId
{
get
{
int userId;
int.TryParse((Id ?? string.Empty).Replace("users/", ""), out userId);
return userId;
}
set { Id = "users/" + value; }
}
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public UserStatus Status { get; set; }
}
Edit 3
As it turns out, when I step through the code, that object is actually of the type Raven.Abstractions.Linq.DynamicJsonObject, which contains an array of key-value pairs. So I guess this question might be more related to Raven than Json.NET. Unless of course there is a converter to go from key-value pair to json object.
It would help to see how you are querying exactly, but you should take a look at the example on querying unlike documents with a multimap index on the RavenDB site.
When I look at your index, it seems like you are trying to do way too much in terms of field storage and encapsulation of your results. It's sometimes difficult to grasp, but the mapping done in the index is not to define how the results are returned, but rather how the index is built. Unless you are doing a Reduce or TransformResults step, you are still returning the original document.
So encapsulating the document as Result = (object)item is overkill. So is having a ResultType enum. If you need to know the type of document that matched, simply use .GetType() on the object and you will quickly see if it is a User or an Asset.
Here is how I would define your search index. Note there's some differences because there were properties you showed in your index that aren't in the models you provided. (I'm assuming there is a separate entity on the backend than the models on the front end, but adjust as needed.)
public class SearchIndex : AbstractMultiMapIndexCreationTask<SearchIndex.Result>
{
public class Result
{
public object[] Content { get; set; }
public string ResultType { get; set; }
}
public SearchIndex()
{
AddMap<Asset>(items => from item in items
select new Result
{
Content = new object[] {item.Name, item.Description},
ResultType = MetadataFor(item)["Raven-Entity-Name"].ToString()
});
AddMap<User>(items => from item in items
select new Result
{
Content = new object[] { item.Username, item.FirstName, item.LastName, item.Email },
ResultType = MetadataFor(item)["Raven-Entity-Name"].ToString()
});
Index(x => x.Content, FieldIndexing.Analyzed);
}
}
And then I would query it like so:
var results = session.Advanced
.LuceneQuery<object, SearchIndex>()
.Where("ResultType:" + resultTypeName)
.AndAlso()
.Search("Content", searchTerm);
You can then simply examine your results and find that while cast as object, you can indeed do result.GetType() and see how that object is constructed. If desired, you could also put a common interface on your entities to cast to instead of object, such as the IAmSearchable shown in the Raven example.
When you finally pass your result back through MVC, it should be serialized properly, since it will be coming from the real object and not the raven DynamicJsonObject.
I'm using jqGrid to display some data on a page. Within the controller action, we're using an anonymous object to represent the data that the jqGrid needs. My question is, is there a way we can create a strongly typed object to represent the jqGrid data that we are sending with Json()?
Main reason for this is so that we can do unit testing with the objects that are being sent to it.
Thanks!
EDIT:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult GridData(FormCollection form, string alias, string location, string state)
{
int pageSize = Convert.ToInt32(form["rows"]);
int pageIndex = Convert.ToInt32(form["page"]) - 1;
var deviceList = this._device.GetList(CreateFilter(location,alias,state),this._securityCache.GetSecurityContext(),pageSize,pageIndex);
int totalResults = deviceList.TotalRecords;
int totalPages = (int)Math.Ceiling((float)totalResults / (float)pageSize);
var jsonData = new {
total = totalPages,
page = pageIndex + 1,
records = totalResults,
rows = (from device in deviceList.Data
select new {i = device.Alias,cell = new string[]{device.Alias,device.Location,device.RatePlan,device.State,device.DateCreated.ToString()}}).ToArray()
};
return Json(jsonData);
This above here works, but we can't unit test the data that is being passed into the Json() method.
var newJsonData = new JsonJQGridReturnData();
newJsonData.total = totalPages;
newJsonData.page = pageIndex + 1;
newJsonData.records = totalResults;
List<JsonJQGridRow> list = new List<JsonJQGridRow>();
foreach (var device in deviceList.Data)
{
list.Add(new JsonJQGridRow(device.Alias, new string[] { device.Alias, device.Location, device.RatePlan, device.State, device.DateCreated.ToString() }));
}
newJsonData.rows = list.ToArray();
_cookieHelper.SaveCookie("DeviceListIndex", this._securityCache.GetSecurityContext().UserID.ToString(), COOKIE_PAGE_SIZE_KEY, pageSize.ToString());
return Json(newJsonData);
}
Here is my poor attempt at trying to wrap these into strongly typed objects. Unfortunately, running this gives me a "u is undefined" in the jqGrid file. I suspect that this is because the json being passed in is not correctly formatted. Here are the classes....
[DataContract]
public class JsonJQGridReturnData
{
[DataMember]
public int total { get; set; }
[DataMember]
public int page { get; set; }
[DataMember]
public int records { get; set; }
[DataMember]
public JsonJQGridRow[] rows { get; set; }
}
[DataContract]
public class JsonJQGridRow
{
public JsonJQGridRow(string i, string[] columns)
{
this.i = i;
this.cells = columns;
}
[DataMember]
public string i { get; set; }
[DataMember]
public string[] cells { get; set; }
}
If I understand your question you can use Generics to do this:
Model:
// represents one row in the JQGrid
class Customer
{
public string firstname { get; set; }
public string lastname { get; set; }
}
JQGrid class:
class JQGridData<TModel>
{
// add in whatever other properties you want for JQGrid
public int responseTime {get; set; };
public List<TModel> rows = new List<TModel>();
}
Controller Action :
public JsonResult GridData(int page)
{
var gridData = new JQGridData<Customer>();
// Populate your data here, this is just an example:
gridData.rows.Add(new Customer()
{
firstname = "fred", lastname = "pharkas"
});
// return the result
return Json(gridData, JsonRequestBehavior.AllowGet);
}
Result:
{
responseTime: 0
rows: [
{
firstname: "fred"
lastname: "pharkas"
}
]
}
Is that what you were asking?
David,
Here's the kinda thing i use in an app i'm working on at the moment for this type of thing. I know it doesn't provide a strongly typed object as such, but the 'list' could be a part of the model that is then sent ToArray() at the end of the piece.
public JsonResult GridData(int id)
{
// get our messages based on id
var bookingmessagesList = _repository.Find(x => x.ID == id);
var list = new ArrayList();
foreach (var bookingmessage in bookingmessagesList) //populate data containers with read data
{
list.Add(new
{
bookingmessage.ClassRowVersionDate,
bookingmessage.ID,
bookingmessage.BookingID,
bookingmessage.AssignedFrom,
bookingmessage.AssignedTo,
bookingmessage.AssignedDate,
bookingmessage.CompletedDate,
bookingmessage.MessageType,
bookingmessage.Notes
});
}
int totalOjectCount = list.Count;
return Json(new { dataitems = list.ToArray(), totalItems = totalOjectCount });
}
hope it gives you some ideas.. Will be interested to see the suggestions made.
Here's a quick take on a strongly-typed JQGridResult.
public class JQGridResult<T> : JsonResult where T : class
{
public T Model
{
get { return (T)this.Data; }
set { this.Data = value; }
}
}
Used as...
return new JQGridResult<JsonModel> {
Model = new GridModel { ... initialize model here ... }
});
where GridModel is basically a container class holding the strongly typed properties for the grid.
I feel really silly. I had a misspelling in the GridRow that was causing jqGrid to blow up. After I fixed that, I was able to get the jqGrid to work with my strongly typed object...
Now in my unit tests, I can just do...
var result = controllerToTest.GridData(form, null, null, null) as JsonResult;
var data = result.Data as JsonJQGridReturnData;
and now I can access the fields :D