Web API Json Responce formatting - c#

I've been searching in many places, but I didn't see this type of scenario
My web api response json is like (I have created a model for this) :
{
"var1": 1,
"test1": 2,
"test2": 3
}
but I want my output response like the following :
{
"type": "test",
"query": "query used",
"result": {
"test1": 2,
"test2": 3
},
"error": "if any error"
}
Do I need to create new model ? or any other easy way?
If I need to create new model, how will I assign existing model object values to new model?

You could create a ResponseDTO model and use it on the return of your Json.
public class ResponseDTO<T>
{
public string Type {get;set;}
public string Query {get;set;}
public T Result {get;set;}
public string Error {get;set;}
}
and on your controller, instead of returning your Model, you return an ResponseDTO, like this:
var response = new ResponseDTO<Model>();
response.Result = new Model(); //Do your things here
Doing it like this makes your response generic, so you can use with any kind of model
UPDATE:
For creating a new model without having to copy all properties, you can use and extension method like this:
public class Model()
{
public int Var1 {get;set;}
public string Test1 {get;set;}
public string Test2 {get;set;}
}
public class NewModel(){
public string Test1 {get;set;}
public string Test2 {get;set;}
}
now you create an extension method, for example "ToNewModel", to convert the old model to the new design you want:
public NewModel ToNewModel(this Model model){
var newModel = new NewModel()
newModel.Test1 = model.Test1;
newModel.Test2 = model.Test2;
}
and them, wherever you have your Model object, just call the extension method:
public JsonResult test()
{
var model = new Model()
//{ Fill your model properties }
var response = new ResponseDTO<NewModel>(); //Declare the response of the type of your new design
response.Result = model.ToNewModel();
}

Related

C# Parsing a IHttpActionResult Json Object returned by a method call

I'm returning a Json object from a method call within another method and would like to ask how to access the properties created within the returned Json object?
I understand that I could return a non Json object with the required properties however how would I access the anonymous type passed into the returned Json
[HttpPost]
public IHttpActionResult PhoneReminder([FromUri] RegisterInterest PhoneReminderValues, int RYI_WebID)
{
var JsonReturned = object1();
// access the Json object like this -> JsonReturned.message
....
//rest of code
}
public IHttpActionResult object1()
{
return new Json(new {message ="hello world"});
}
Get Newtonsoft.Json from NuGet.
And then you can do it this way:
public async Task<T> GetObjectFromContent<T>(HttpContent content) where T: class
{
string response = await content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(response))
return null;
try
{
T obj = JsonConvert.DeserializeObject<T>(response);
return obj;
}
catch(JsonSerializationException)
{
return null;
}
}
Firstly I get a string response from HttpContent. It's really just a json in string.
Then JsonConvert.DeserializeObject is used. Of course you have to declare first the class. For example, if you have Json like this:
{
"FirstName" : "John",
"SecondName" : "Black"
}
then you have to create class:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
And call this method (GetObjectFromContent) with Person as T.
Your class should have a parameteless constructor.
You can also give differen names for your properties, but you will have to decorate them with attribute JsonProperty
Use Nuget Newtonsoft.Json
if suppose your JSON object is like:
HttpResponseMessage response;
var jsonObject = await response.Content.ReadAsStringAsync();
Now suppose you have one property "FirstName" in the JSON which you want to access
You can do it like below:
using Newtonsoft.Json.Linq;
var parsedJsonObject = JObject.Parse(jsonObject);
var firstName = parsedJsonObject["FirstName"];

C# Deserialize List<someobject> restfully with ServiceStack

I'm attempting to receive a POSTed List of POCO but I'm unable to deserialize either via the Swagger API or via Postman when submitting over the wire. I've serialized the object back out to confirm how it supposed to be serialized, but when returning that back the body of the form, the request object parameter is null.
public class NameValuePair
{
public string Name { get; set; }
public string Value { get; set; }
}
public class NameValueList
{
private List<NameValuePair> valuesToProcess = null;
public List<NameValuePair> ValuesToProcess { get { return valuesToProcess; } set { valuesToProcess = value; } }
public NameValueList()
{
valuesToProcess = new List<NameValuePair>();
}
}
[Api("A description of what the API does")]
[Tag("Enriching Requests")]
[ApiResponse(HttpStatusCode.BadRequest, "Your request was not understood")]
[ApiResponse(HttpStatusCode.InternalServerError, "Oops, something broke")]
[Route("/EnrichValueList", "POST", Summary = "Summary of the Web Get method", Notes = "Longer information about what this service does")]
public class EnrichValueList : IPost, IReturn<EnrichValueListResponse>
{
[ApiMember(Name = "NameValues", Description = "A string that represents a value with which to understand more information about", ParameterType = "body", DataType = "NameValueList", IsRequired = true)]
public NameValueList NameValues
{
get;
set;
}
[ApiMember(Name = "AssociatedActivities", Description = "A comma seperated string that links Enrichment Activities with this value", ParameterType = "body", DataType = "string", IsRequired = false)]
public string AssociatedActivities
{
get;
set;
}
}
The request.NameValues in this case is null (no error is thrown):
public async Task<EnrichValueListResponse> Post(EnrichValueList request)
{
EnrichValueListResponse enrichValueListResponse = new EnrichValueListResponse();
return enrichValueListResponse;
}
I've already got other methods that receive a string of stringyfied object and then use the JsonSerializer.DeserializeFromString method from ServiceStack.Text so completely fine with that approach. I was attempting to use a more strongly typed object in the original request (which may not be possible or I'm doing it wrong).
Param: NameValues, Value {"valuesToProcess":[{"name":"bob","value":"Not Bob"}]}
and trying about every other permutation I can think of. Interestingly, when changing to plain string parameters and posting, the inbuilt swagger API returns a deserialization error, but Postman is fine.
Swagger Top Half
Swagger Bottom Half
Response Body as text
{
"responseStatus": {
"errorCode": "SerializationException",
"message": "Type definitions should start with a '{', expecting serialized type 'EnrichValueList', got string starting with: \"two\"",
"stackTrace": " at ServiceStack.Text.Common.DeserializeTypeRefJson.StringToType(ReadOnlySpan`1 strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair`2[] typeAccessors)\r\n at ServiceStack.Text.Common.DeserializeType`1.StringToTypeContext.DeserializeJson(ReadOnlySpan`1 value)\r\n at ServiceStack.Text.Json.JsonReader.<>c__DisplayClass3_0.<GetParseSpanFn>b__0(ReadOnlySpan`1 v)\r\n at ServiceStack.Text.JsonSerializer.DeserializeFromSpan(Type type, ReadOnlySpan`1 value)\r\n at ServiceStack.Memory.NetCoreMemory.Deserialize(MemoryStream memoryStream, Boolean fromPool, Type type, DeserializeStringSpanDelegate deserializer)\r\n at ServiceStack.Memory.NetCoreMemory.DeserializeAsync(Stream stream, Type type, DeserializeStringSpanDelegate deserializer)\r\n at ServiceStack.Host.RestHandler.CreateRequestAsync(IRequest httpReq, IRestPath restPath, Dictionary`2 requestParams)\r\n at ServiceStack.Host.RestHandler.CreateRequestAsync(IRequest httpReq, IRestPath restPath)\r\n at ServiceStack.Host.RestHandler.ProcessRequestAsync(IRequest req, IResponse httpRes, String operationName)"
}
}
Postman
Update
Following #mythz advice, I removed both the ParameterType and the DataType from the decorator and I was able to exhibit some slightly different behaviour.
Using the example classes:
public class NameValues
{
public string Name { get; set; }
public List<string> Values { get; set; }
public NameValues()
{
Values = new List<string>();
Name = string.Empty;
}
}
public class NameValuesList
{
public List<NameValues> ValuesToProcess { get; set; }
public NameValuesList()
{
ValuesToProcess = new List<NameValues>();
}
}
and setting the DTO parameter to this
[ApiMember(Name = "NameValues", Description = "A string that represents a value with which to understand more information about", IsRequired = true)]
public NameValuesList NameValues
{
get;
set;
}
causes the same deserialization error when I pass in a JSON structure that should deserialize. However, if I pass in some deformed string, it throws no error and just runs on through to the IPost handler method with a null for the property.
If I change the API parameter back to a string and use this example to show serialization and deserialization using the ServiceStack.Text library, works like a charm through both Swagger and Postman.
public async Task<EnrichValueListResponse> Post(EnrichValueList request)
{
EnrichValueListResponse enrichValueListResponse = new EnrichValueListResponse();
// Create a dummy object to serialize as JSON to return as an example back to the caller
NameValuesList stuff = new NameValuesList();
stuff.ValuesToProcess.Add(new NameValues { Name = "first", Values = { "second", "third" } });
enrichValueListResponse.BatchId = await Task.Run(() => stuff.ToJson().IndentJson());
// Deserialize the inbound string
NameValuesList betterStuff = JsonSerializer.DeserializeFromString<NameValuesList>(request.NameValues);
return enrichValueListResponse;
}
JSON submitted (although I did try many different variations of encoding and structure).
{
"valuesToProcess": [
{
"name": "first",
"values": [
"second",
"third"
]
}
]
}
I've got debug mode set, but not seeing any exceptions thrown to the SeriLog db during parsing. For now, I'll run with string parameter and derserialize after the fact. I can do some pre-checking in the Fluent Validator

How to have a unique C# code with different Entities EF having the same columns

Good morning everybody,
I am doing a AngularJS project using ASP.NET-MVC, C#, EF and an SQL Express DB.
I have an HTML page calling some AngularJS functions calling some functions on MyController.cs.
In MyController.cs I have quite a lot functions using EF.
In my DB, I have hundred of tables with the same columns.
And I want to have the same HTML page for each table, so executing the same functions with different names
For example when I go to the link http://..../Index/TABLE1, MyController.cs would look like :
public ActionResult getCaptions()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = 500000000;
var data =
_db
.TABLE1
.OrderBy(i => i.CodeId)
.ToArray();
return Content(serializer.Serialize(data).ToString(), "application/json");
}
and when I go to the link http://..../Index/TABLE2, MyController.cs would look like :
public ActionResult getCaptions()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = 500000000;
var data =
_db
.TABLE2
.OrderBy(i => i.CodeId)
.ToArray();
return Content(serializer.Serialize(data).ToString(), "application/json");
}
I have thought about a solution like this :
Declare a global variable on the controller tableName
Modify the Index ActionResult
public ActionResult Index(string id)
{
tableName = id;
return View();
}
Now I am stuck ...
Any help is needed, thanks.
EDIT : If you downvote, can you at least explain why ? Thanks
I see you #aBennouna may have already given up on this question, but I took an interest in the question and decided it needed a solution. It may not be 100% what you asked for since here you can't take in a table name as a string parameter.
First if all the tables have same columns, you can inherit them from a same base:
public class TableBase
{
[Key]
public int CodeId { get; set; }
public int Prop1 { get; set; }
public int Prop2 { get; set; }
public int Prop3 { get; set; }
}
Using this base we can define our tables:
public class Table1 : TableBase
{
}
public class Table2 : TableBase
{
}
// etc...
This enables us to write a generic GetCaptions method like #CodeCaster suggested (thanks for the nudge in right direction):
public ActionResult GetCaptions<T>() where T : TableBase
{
var set = db.Set<T>();
// get all objects to array
var list = set.OrderBy(i => i.CodeId).ToList();
// serialize and return result
// OR get single object and a value
var item = set.FirstOrDefault();
var propertyValue = item.Prop1;
}
Usage:
GetCaptions<Table1>();
GetCaptions<Table2>();

dealing with dynamic properties on oData client

I have the following class on both server and client
public class Entity
{
public string Id {get; set;}
public string Name {get; set;}
public Dictionary<string, object> DynamicProperties {get; set;}
}
As far as I have seen all the examples of open type describes about having dynamic properties on the server side, but the properties on the client needs to be explicitly declared.When I send a POST request from the client how do i send the dynamic properties ?. I can't declare all the dynamic properties on the client side. There are numerous properties and each object will contain different set of dynamic properties in the client side. These dynamic properties are stored in the DynamicProperties dictionary in the client side. How do I send the object of above entity class to the server side, so that server will interpret the contents of DynamicProperties dictionary as dynamic properties ?. Any help is appreciated.
===========================Follow-up for sam's answer=======================
static void Main(string[] args1)
{
container.Customers.ToList();
Customer newCustomer = new Customer();
newCustomer.Id = 19;
newCustomer.Properties = new Dictionary<string, object>
{
{"IntProp", 9},
{"DateTimeOffsetProp", new DateTimeOffset(2015, 7, 16, 1, 2, 3, 4, TimeSpan.Zero)},
{"blah","ha"}
};
try
{
addCustomer(newCustomer);
container.AddToCustomers(newCustomer);
container.SaveChanges();
}
catch (Exception)
{
}
Customer newCustomer1 = new Customer();
newCustomer1.Id = 20;
newCustomer1.Properties = new Dictionary<string, object>
{
{"IntProp", 10},
{"dir","north"}
};
addCustomer(newCustomer1);
container.AddToCustomers(newCustomer1);
container.SaveChanges();
newCustomer1.Properties["dir"] = "south";
container.UpdateObject(newCustomer1);
container.SaveChanges();
Console.ReadKey();
}
private static void addCustomer(Customer customer)
{
container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
foreach (var property in customer.Properties)
{
args.Entry.AddProperties(new ODataProperty
{
Name = property.Key,
Value = property.Value // for enum, complex type, should to create ODataEnumValue and ODataComplexValue.
});
}
});
}
I am getting an error stating Multiple properties with the name 'IntProp' were detected in an entry or a complex value. In OData, duplicate property names are not allowed. Also, I doubt if creating an action each time before sending an object like how I am doing now is a valid approach as I get lot of objects from a source and I send it to the server. If I create an action for each object then it might blow up the memory as oData client holds these actions in memory. How do I handle my scenario ?. Kindly help me.
Also, one more question if I comment the container.Customers.ToList() it fails stating that I am trying to add undeclared properties. Why is that ?
If you are using OData Client Code Generator, you can use the partial class to define/retrieve/save the dyanmic properties.
For example, in your client side, you can define a partial class for your Entity
public partial class Entity
{
// Dynamic property "Email"
[global::Microsoft.OData.Client.OriginalNameAttribute("Email")]
public string Email
{
get
{
return this._Email;
}
set
{
this.OnEmailChanging(value);
this._Email = value;
this.OnEmailChanged();
this.OnPropertyChanged("Email");
}
}
private string _Email;
partial void OnEmailChanging(string value);
partial void OnEmailChanged();
}
Then, you can use this to insert/retrieve/save the dynamic property "Email".
You can do like this:
Container container = new Container(new Uri("http://..."));
Entity entity = new Entity();
...
entity.Email = "xxxx";
container.AddToEntities(entity);
container.SaveChanges();
For similar implementation, you can refer to my sample project.
========== iteration 2 ================
For client Entity class with IDictionary<string,object>, I think the hook is what you're looking for.
For example, on client side:
public partial class Entity
{
public IDictionary<string, object> Properties { get; set; }
.....
}
It should work if you insert the following codes before
container.AddToEntities(entity);
For example:
Entity entity = new Entity();
...
entity.Properties = new Dictionary<string, object>
{
{"IntProp", 9},
{"DateTimeOffsetProp", new DateTimeOffset(2015, 7, 16, 1, 2, 3, 4, TimeSpan.Zero)}
};
container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
foreach (var property in entity.Properties)
{
args.Entry.AddProperties(new ODataProperty
{
Name = property.Key,
Value = property.Value
});
}
});
container.AddToEntities(entity);
container.SaveChanges();
Where, AddProperties is an extension method. You can find it in my sample project
and the latest commit
Besides, the hood method only works with OData Client V6.12 or above.
Hope it can help you.
========== iteration 3 ================
First, you call the following method,
container.Configurations.RequestPipeline.OnEntryStarting(...);
It means to add an action which will be called in later execution. In your codes, you call it twice, So, there are two actions added. These two actions will be called one by one when execute to save your newCustomer1
That's, newCustomer1 will have newCustomer's dynamic properties (action 1), meanwhile, it will have its own dynamic properties (action 2). That's why you got the duplicate property name exception.
To resolve it, you can just to renew a Container. See my project's update.
For container.Customers.ToList(), it seems an OData client issue.
[Answering my own question : Another approach]
Extending Sam Xu's approach for iteration 2. We can do it as below. (For the sake of clarity let's assume the name of the class in question as Book)
public partial class Book
{
public string ISBN {get; set;}
public IDictionary<string, object> DynamicProperties { get; set; }
}
// This portion can be put in a function and can be invoked only once
container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
if(args.Entity.GetType() == typeof(Book))
{
var book = args.Entity as Book
foreach (var property in book.DynamicProperties)
{
args.Entry.AddProperties(new ODataProperty
{
Name = property.Key,
Value = property.Value
});
}
}
});
AddProperties extension method implementation is provided in Sam Xu's implementation

Calling a constructor on custom view model changes output type to JSON

I'm developing a WebAPI service and have been confronted with a curious problem. When calling a ViewModel with a constructor why is the return type changed to JSON from XML?
Code from controller;
// GET api/Product/5
public MyViewModel GetProduct(Int64 id)
{
// without a constructor this returns an xml
//return new MyViewModel() { Name = "123" };
// this changes type to json
Product product = new Product();
return new MyViewModel(product) { Name = "123" };
}
View Model class;
[XmlRoot(ElementName = "ARequest", Namespace = "http://myschema.com/schemas/myviewmodel.xsd")]
public class MyViewModel : Product
{
public string Name { get; set; }
public MyViewModel(Product product)
{
// this constructor causes the type to switch from
// xml to json - why?
}
}
It seems that this is some weird behavior of the serializer. Add a default empty constructor to your model along with the other constructor:
public MyViewModel()
{
}
public MyViewModel(Product product)
{
}
But personally I would use a view model. A real one. Not some hybrid to which you are passing your domain model. Just have a simple POCO as view model. And a mapping layer that will map from the domain model.

Categories