Serialize enum to const JsonNet - javascript

I am using Asp MVC 3 application.
I have an Enum:
public enum EmployeesOptions
{
John = 1,
Peter = 2,
Andrew = 3
}
And a MyViewModel class
public class MyViewModel
{
public MyViewModel()
{
Employees = new List<EmployeesOptions>()
{
EmployeesOptions.John,
EmployeesOptions.Peter,
EmployeesOptions.Andrew
};
}
public IEnumerable<EmployeesOptions> Employees { get; set; }
}
My Controller:
public ActionResult Index()
{
var vm = new MyViewModel();
return View(vm);
}
In My Index View:
#model MyViewModel
<script type="text/javascript">
var jsonString = '#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(this.Model))';
var data = ko.mapping.fromJSON(jsonString);
omega.franchiseInfo = ko.mapping.fromJS(data);
</script>
My serialized data coming from the server looks like this:
Emplyees:[1,2,3]
I want to be like this:
Emplyees:["John","Peter","Andrew"]
What am I missing ?
Update:
var jsonString = '#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(this.Model, Newtonsoft.Json.Formatting.None, new Newtonsoft.Json.Converters.StringEnumConverter()))';
This do the job!

If you want this enum type always to be serialized with its string values, you can decorate it with a JsonConverter attribute and the StringEnumConverter class like this:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
[JsonConverter(typeof(StringEnumConverter))]
public enum EmployeesOptions
{
John = 1,
Peter = 2,
Andrew = 3
}
Then you don't need to specify any converter classes in the serializer options anymore.

I tried decorating a List property that holds Enum values with [JsonConverter(typeof(StringEnumConverter))] but understandably that didn't work since it should decorate the Enum type directly.
// Did not work!
[JsonConverter(typeof(StringEnumConverter))]
public List<Assessment.AssessmentFunction> SelectedFunctions { get; set; }
then I did as you suggested and it worked as expected.
var selectedFunctions = #Html.Raw(JsonConvert.SerializeObject(Model.SelectedFunctions,
new StringEnumConverter()))
Instead of Enum int values now I get Enum strings in the JavaScript code inside a Razor .cshtml view. Just what I needed in a specific situation.
Before
var selectedFunctions = #Html.Raw(Json.Encode(Model.SelectedFunctions))
// Output
var selectedFunctions = [3, 3, 2, 2, 2, 3, 2, 2]
After
var selectedFunctions = #Html.Raw(JsonConvert.SerializeObject(Model.SelectedFunctions,
new StringEnumConverter()))
// Output
var selectedFunctions = ["Nurse","Nurse","Doctor","Doctor","Doctor","Nurse","Doctor","Doctor"]

You are returning enums, and by default it will display the enum values. You can modify your model like this.
public class MyViewModel
{
public MyViewModel()
{
Employees = new List<EmployeesOptions>()
{
EmployeesOptions.John.ToString(),
EmployeesOptions.Peter.ToString(),
EmployeesOptions.Andrew.ToString()
};
}
public IEnumerable<EmployeesOptions> Employees { get; set; }
}
By using the .ToString() extension method we can convert enums to the exact thing they are representing to string format.

Related

How can I convert javascript var obj = {}; to C#?

I have the following javascript code:
var key = "Mykey" + NextNumber.toString();
var value = {"Name":"Tony","Width":"150","Height":"320"};
var valuejson = JSON.stringify(value);
var obj = {};
obj[key] = valuejson
I know how to create valuejson in C#, but I don't know how to create something similar like var obj = {}; in C#. How can I do that in C#?
key and valuejson in C#:
public class MyValue
{
public string Name { get; set; }
public string Width { get; set; }
public string Height { get; set; }
}
MyValue value = new MyValue();
value.Name = "Tony";
value.Width = "150";
value.Height = "320";
string jsonValue = JsonConvert.SerializeObject(value);
string key = "Mykey" + NextNumber.toString();
You could try to use a dynamic object which works similar to {} in javascript... But... You have to be CAREFUL, example:
public class test
{
public class MyValue
{
public string Name { get; set; }
public string Width { get; set; }
public string Height { get; set; }
}
public void testing()
{
MyValue value = new MyValue();
value.Name = "Tony";
value.Width = "150";
value.Height = "320";
dynamic jsonValue = new { keyA = value };
string height = jsonValue.keyA.Height;
}
}
EDI:
Actually, I read a bit more carefully your need, and a dictionary can also suit your needs:
public class test
{
public class MyValue
{
public string Name { get; set; }
public string Width { get; set; }
public string Height { get; set; }
}
Dictionary<string, MyValue> dic = new Dictionary<string, MyValue>();
public void testing()
{
string key = "Mykey" + NextNumber.toString();
MyValue value = new MyValue();
value.Name = "Tony";
value.Width = "150";
value.Height = "320";
dic.Add(key, value);
}
}
Since you where asking for the equivalent of a var x = {} I suggested the dynamic but I see you want to create a key and associate that value to that key.
If you're looking for an object whose members can be dynamically added and removed at run time (like in Javascript) then the ExpandoObject class should fit your needs.
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
foreach (var property in (IDictionary<String, Object>)employee)
{
Console.WriteLine(property.Key + ": " + property.Value);
}
// This code example produces the following output:
// Name: John Smith
// Age: 33
You are asking for dynamic ExpandoObject.
Example:
dynamic obj = new ExpandoObject();
obj.banana = "CIAO";
obj.bidshmqwq = 11245;
obj.BRUFCJMWH = null;
In substance, this Type can let you declare object's properties dynamically.
To convert from a json string to a C# object, you can use the DeserializeObject method and pass in an instance of the c# object that you want to convert this json to. The JsonConvert library is part of the Newtonsoft.Json library.
var converted = JsonConvert.DeserializeObject<myCSharpViewModel>(json);

Is it possible to have a method in C# that implicitly deserializes an argument if it's passed as a JSON string?

Question
I have a handful of ViewComponents that look like so:
public IViewComponentResult Invoke(BuyerViewModel buyer)
I'd like them to be able to accept either a BuyerViewModel, or a JSON string representing a BuyerViewModel. For example, when you pass JSON to a controller method from JavaScript, if that method expects an argument of type Dog, the controller automatically attempts to deserialize the JSON to an instance of Dog. I'm trying to mimic that behavior.
The goal would be that both of these examples work:
var buyer = new BuyerSummaryViewModel() { FirstName = "John" };
ViewComponent("Buyer", buyer);
ViewComponent("Buyer", "{\"Name\":\"John Smith\"}");
Why?
I'm trying to make a generic JavaScript method that can fetch a ViewComponent on the fly:
const fetchViewComponent = async (viewComponentName, viewModel) => {
let data = { viewComponentName, viewModel };
let html = await $.get(`/Order/FetchViewComponent`, data);
return html;
}
//Get a BuyerViewComponent (example)
(async () => {
let component = await fetchViewComponent("Buyer", `#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Buyer))`);
console.log(component);
})();
What I've Tried
If I specify that the ViewModel is a BuyerViewModel, it works. The JSON string is automatically deserialized into a BuyerViewModel.
public class FetchViewComponentRequest
{
public string ViewComponentName { get; set; }
public BuyerViewModel ViewModel { get; set; }
// ^^^^^^^^^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
The Issue
However, I don't want to specify the type; I want this to be generic. So I tried this:
public class FetchViewComponentRequest
{
public string ViewComponentName { get; set; }
public string ViewModel { get; set; }
// ^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
But as expected, request.ViewModel isn't the correct type; it ends up null in the Invoke method. I was hoping there was a flag or something more global I could specify so that it tries to implicitly deserialize this string into the expected type.
Is there an easier way to do this that I haven't considered? Or, if not, is the way I'm envisioning even possible?
(I'm using .NET Core 2.2)
Maybe make your FetchViewComponentRequest generic?
public class FetchViewComponentRequest<T>
{
public string ViewComponentName { get; set; }
public T ViewModel { get; set; }
// ^^^^^^^^^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest<BuyerViewModel> request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
The method needs to have some knowledge of what type to make the object coming in.
public T Convert<T>(dynamic obj) where T:class,new()
{
T myob = null;
if (obj !=null && obj is T)
{
myob = obj as T;
}
else if (obj is string)
{
//convert to type
myob = JsonConvert.DeserializeObject<T>(obj);
}
return myob;
}
Ok, im not sure about what you need.
But here is a dynamic way to do it, without specifying <T>.
//Assume that the namespace is DynamicTypeDemo
public class DynamicType {
// eg "DynamicTypeDemo.Cat, DynamicTypeDemo"
public string TypeName { get; set; } // the full path to the type
public string JsonString { get; set; }
}
Now you could simple DeserializeObject
public object ToObject(DynamicType dynamicType){
var type = Type.GetType(dynamicType.TypeName);
// Here you could check if the json is list, its really upp to you
// but as an example, i will still add it
if (dynamicType.JsonString.StartsWith("[")) // its a list
type =(List<>).MakeGenericType(type);
return JsonConvert.DeserializeObject(dynamicType.JsonString, type);
}
And here is how it work
var item = new DynamicType(){
TypeName = "DynamicTypeDemo.Cat, DynamicTypeDemo", // or typeof(Cat).AssemblyQualifiedName
JsonString = "{CatName:'Test'}"; // And for a list "[{CatName:'Test'}]"
}
object dynamicObject= ToObject(item); // return it to the javascript
Cat cat = dynamicObject as Cat; // Cast it if you want

Why is axios response in camel case when sending a request in asp.net core [duplicate]

I'm running through a WintellectNOW course on ASP.NET Core/Web API/Angular 2. I have the API portion implemented, but for whatever reason, the JSON that is being returned has the variable names being lowercased.
The returned JSON is formatted like...
[
{"id":1,"name":"Bowler","color":"black","count":1},
{"id":2,"name":"Fedora","color":"red","count":1},
{"id":3,"name":"Baseball Cap","color":"blue","count":3}
]
I'm expecting...
[
{"Id":1,"Name":"Bowler","Color":"black","Count":1},
{"Id":2,"Name":"Fedora","Color":"red","Count":1},
{"Id":3,"Name":"Baseball Cap","Color":"blue","Count":3}
]
Based on the C# model of...
namespace HatCollection.Models
{
public class Hat
{
public int Id { get; set; }
public string Name { get; set; }
public string Color { get; set; }
public int Count { get; set; }
}
}
I even went as far as decorating the properties with [DataMember(Name = "Id")] just to make sure and it still didn't matter.
On the off chance, it's relevant the Action and instance variable in the controller...
private static readonly List<Hat> MyHats = new List<Hat>
{
new Hat {Id = 1, Name = "Bowler", Color = "black", Count = 1 },
new Hat {Id = 2, Name = "Fedora", Color = "red", Count = 1 },
new Hat {Id = 3, Name = "Baseball Cap", Color = "blue", Count = 3 }
};
[HttpGet]
public IEnumerable<Hat> Get()
{
return MyHats;
}
How do I turn off the camelCase functionality, so that ASP.NET Core returns the property names without changing them?
In Asp.Net Core 3.0 some things have changed. For camelCase do nothing that is out of the box. For PascalCase or another set style use.
services.AddMvc(setupAction=> {
setupAction.EnableEndpointRouting = false;
}).AddJsonOptions(jsonOptions =>
{
jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
In Startup.cs ConfigureServices section
For those who needs a solution about a PascalCase within Api Project that has not the Mvc services you should add this after AddControllers services
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddJsonOptions(jsonOptions =>
{
jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null;
} ;
}
For Asp.Net Core 3.1 using the NewtonSoft.Json
services.AddControllers()
.AddNewtonsoftJson(options =>
{
options.UseMemberCasing();
});
In ASP.NET Core <3.0, JSON properties are camelCased by default (per this announcement).
You can disable this by replacing
services.AddMvc();
with
services
.AddMvc()
.AddJsonOptions(opt => opt.SerializerSettings.ContractResolver
= new DefaultContractResolver());
in your Startup.cs file. You'll have to add using Newtonsoft.Json.Serialization; to the top of the file.
With the DefaultContractResolver in place, the property names will be represented verbatim in the JSON output. No need for DataMember attributes.
Here is the answer for .net 5 :
https://learn.microsoft.com/en-us/aspnet/core/web-api/advanced/formatting?view=aspnetcore-5.0
Configure System.Text.Json based formatters Features for the
System.Text.Json based formatters can be configured using
Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions.
The
default formatting is camelCase. The following highlighted code sets
PascalCase formatting:
C#
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddJsonOptions(options =>
options.JsonSerializerOptions.PropertyNamingPolicy = null);
}
Another solution in Asp.Net.Core 2.2 as following:
services.AddMvc()
.AddJsonOptions(jsonOptions => jsonOptions.UseMemberCasing())
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
In ASP.Net Core you can use two way:
First way: UseMemberCasing()
In StartUp.cs :
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews().AddNewtonsoftJson(opt =>
{
opt.UseMemberCasing(); // <-- add this
});
}
Second way: ContractResolver
In StartUp.cs :
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews().AddNewtonsoftJson(opt =>
{
opt.SerializerSettings.ContractResolver = new DefaultContractResolver(); // <-- add this
});
}
depends on your project maybe you used AddMvc() or AddControllers() insted of AddControllersWithViews().
If AddNewtonsoftJson not found, you should install Nuget pacage : Microsoft.AspNetCore.Mvc.NewtonsoftJson (link).
You have to change the DefaultContractResolver which uses camelCase by default. Just set the NamingStatergy as null.
This should be done in the StartUp.ConfirgureService as follows.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddMvcOptions(o => o.OutputFormatters.Add(
new XmlDataContractSerializerOutputFormatter()));
.AddJsonOptions(o => {
if (o.SerializerSettings.ContractResolver != null)
{
var castedResolver = o.SerializerSettings.ContractResolver
as DefaultContractResolver;
castedResolver.NamingStrategy = null;
}
});
}
Option 2
Use JSonProperty as follows.
public class Hat
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("color")]
public string Color { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
}
I am using the following solution because
a) I prefer using the .Net Core built in System.Text.Json serializer and
b) I do not want to rely on the not documented internal behaviour of
jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null;.
.
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = new MyTransparentJsonNamingPolicy();
});
where:
public class MyTransparentJsonNamingPolicy : JsonNamingPolicy
{
// You can came up any custom transformation here, so instead just transparently
// pass through the original C# class property name, it is possible to explicit
// convert to PascalCase, etc:
public override string ConvertName(string name)
{
return name;
}
}
In .NET 6 I used:
builder.Services.AddControllersWithViews().AddJsonOptions(opt => opt.JsonSerializerOptions.PropertyNamingPolicy = null);

Store Model as JSON in Hidden input and access it in javascript

How do I store a Model in a hidden input and access it in my javascript function?
I am storing the model in a hidden field as
string defaultFareListJson =
Newtonsoft.Json.JsonConvert.SerializeObject(#Model.DefaultFare);
#Html.Hidden("DefaultFareList", defaultFareListJson);
And in my Javascript function, I am trying to access it as:
function viewDefaultFareSchedule() {
var defaultFareObject = {}
defaultFareObject.Fares = jQuery.parseJSON($('#DefaultFareList').val());
alert(defaultFareObject.Fares[0].facility);
}
My ViewModel is as follows:
public class NavBarCallerViewModel
{
public FareSchedViewModel DefaultFare { get; set; } = new FareSchedViewModel();
}
public class FareSchedViewModel {
public string facility{get;set;}
}
NH
I was able to parse a hidden JSON string("DefaultFareList": converted from Model) as :
var defaultFareString = document.getElementById('DefaultFareList').value;
var defaultFare = JSON.parse(defaultFareString);

ASP.NET MVC - How to "reverse" model binding to convert a C# model back to a query string representation

I have a custom javascript on the client side that I use to build up a querystring and pass over to my asp.net-mvc controller
var templateQueryString = BuildTemplate();
$.ajax({
url: '/MyController/Save?' + templateQueryString,
type: 'post',
dataType: 'json',
success: function (data) {
}
}
and on my controller all of the properties leverage the model binding so it comes in as a single object on the server side. NOTE: that this is a pretty complex object with arrays and arrays of sub objects:
public ActionResult Save(MyTemplate template)
{
}
the issue now is that I need to be able to convert from my C# object back to a string that represents "myTemplateQueryString" on the client side.
Is there any recommended way to take an object and do the "reverse" model binding. They key here is that it generates a string that I could use as a query string again in the future to pass into another asp.ent-mvc controller action.
Here is an example of the querystring that I am storing locally:
<input type="hidden" value="showIds=false&showRisks=false&
amp;statusIds=2&statusIds=1&statusIds=6&statusIds=8&
amp;statusIds=3&statusIds=9&showCompleted=0"
name="filterQueryString" id="filterQueryString">
As #haim770 said it would be easier if you used JSON in the request payload, and not the query string to pass your complex object to the server.
Regarding creating the query string from a model there is not a built-in method that does something like that or any recommended approach as far as i know. An obvious solution is to use reflection and build the query string from your properties.
Assuming your BuildTemplate class looks something like:
public class BuildTemplate
{
public bool ShowIds { get; set; }
public bool ShowRisks { get; set; }
public bool ShowCompleted { get; set; }
public int[] StatusIds { get; set; }
}
You can develop an extension method to convert any object to a QueryString. Here is some initial code you can start with:
public static class ObjectExtensions
{
public static string ToQueryString(this Object obj)
{
var keyPairs = obj.GetType().GetProperties().Select(p =>
new KeyValuePair<string, object>(p.Name.ToLower(), p.GetValue(obj, null)));
var arr = new List<string>();
foreach (var item in keyPairs)
{
if (item.Value is IEnumerable && !(item.Value is String))
{
foreach (var arrayItem in (item.Value as IEnumerable))
{
arr.Add(String.Format("{0}={1}", item.Key, arrayItem.ToString().ToLower()));
}
}
else
arr.Add(String.Format("{0}={1}", item.Key, item.Value.ToString().ToLower()));
}
return "?" + String.Join("&", arr);
}
}
Then you can easily invoke this code on any object to generate a query string:
var person = new BuildTemplate() { StatusIds = new []{ 1, 5, 8, 9 }, ShowRisks = true };
var queryString = person.ToQueryString();
This would generate a query string like:
"?showids=false&showrisks=true&showcompleted=false&statusids=1&statusids=5&statusids=8&statusids=9"
This query string should work just fine with the default model binder for the BuildTemplate class.

Categories

Resources