JSON.NET Serializer for WCF REST Services - json.net

I am trying to use the NETFx Json.NET MediaTypeFormatter nuget package to swap out the default DataContractJsonSerializer in my WCF REST service (4.0 framework). I downloaded the package in my project and added the following lines of code in the Global.asax file.
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
// Create Json.Net formatter serializing DateTime using the ISO 8601 format
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
var config = HttpHostConfiguration.Create();
config.Configuration.OperationHandlerFactory.Formatters.Clear();
config.Configuration.OperationHandlerFactory.Formatters.Insert(0, new JsonNetMediaTypeFormatter(serializerSettings));
}
But when I run the service it still uses the DataContractJsonSerilizer for serialization. Below is the class I am returning from my service.
[DataContract]
public class SampleItem
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string StringValue { get; set; }
[DataMember]
public DateTime DateTime { get; set; }
}
Below is the response from the service in Fiddler.
You can see that the DateTime is not in ISO format which I have specified in serializerSettings in the above code. This tells me that the JSON.NET serializer is not used for serializing the objects.
Would appreciate any help.

I feel dumb after I figured the answer. Happens at times :). I had to add the config to the RouteTable. Below is the code in Global.asax
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
// Create Json.Net formatter serializing DateTime using the ISO 8601 format
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
var config = HttpHostConfiguration.Create().Configuration;
config.OperationHandlerFactory.Formatters.Clear();
config.OperationHandlerFactory.Formatters.Insert(0, new JsonNetMediaTypeFormatter(serializerSettings));
var httpServiceFactory = new HttpServiceHostFactory
{
OperationHandlerFactory = config.OperationHandlerFactory,
MessageHandlerFactory = config.MessageHandlerFactory
};
RouteTable.Routes.Add(new ServiceRoute("Service1", httpServiceFactory, typeof(Service1)));
}
}
Hope it will help somebody if they happen to run into the same scenario.

Related

Global json serialization option in .Net Core 3.x

I have .Net Core 3.1 Web Api. I am using System.Text.Json serializer since it became a default for .Net Core 3.x applications. I have set global enum to string converter as follows:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddControllers()
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())));
...
}
Enums are converted to string for controller responses (which makes sense since I configure on AddControllers() method). But if I try to manually serialize an object it still serializes enum as int. Sample below:
public class TestClass
{
public void Test()
{
var data = JsonSerializer.Serialize(new MyObject { Enum1 = MyEnum.Value1, Enum2 = MyEnum.Value2 });
}
public class MyObject
{
public MyEnum Enum1 { get; set; }
public MyEnum Enum2 { get; set; }
}
public enum MyEnum
{
Value1 = 1,
Value2 = 2
}
}
OUTPUT:
data [string]: "{\"Enum1\":1,\"Enum2\":2}"
If I add conversion attribute manually then it serializes as desired:
public class MyObject
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public MyEnum Enum1 { get; set; }
public MyEnum Enum2 { get; set; }
}
OUTPUT
data [string]: "{\"Enum1\":\"Value1\",\"Enum2\":2}"
Is there a way to set global json serialization options (enum to string conversion) that would apply for manual serialization as well?
Or maybe I should just always stick to the explicit attributes?
Currently you can't. JsonSerializer being a static class with only purely static methods, default options cannot be set. You can check this open issue on Github. It seems that it has been designed this way for better performance.
As an alternative, you can create your own static class
public static class CustomJsonSerializer
{
private static JsonSerializerOptions serializerSettings =
new JsonSerializerOptions { /* whatever you need */};
public static T Deserialize<T>(this string json)
{
return JsonSerializer.Deserialize<T>(json, serializerSettings );
}
// etc.
}
I managed to get this to work by adding NewtonsoftJson and then register StringEnumConverter:
services
.AddControllers(jsonOptions => jsonOptions.ReturnHttpNotAcceptable = true)
.AddNewtonsoftJson(jsonOptions =>
{
jsonOptions.SerializerSettings.Converters.Add((JsonConverter) new StringEnumConverter());
}

Export / Import Xamarin.Essentials Preferences

I was looking for a quick / simple way to import and export the Preferences object exposed by Xamarin.Essentials. Any suggestions?
According to your description, you want to save data in preference and get data from Preferences, am I right? if yes, please take a look the following code:
using Xamarin.Essentials;
private void Btn1_Clicked(object sender, EventArgs e)
{
Preferences.Set("key1", "this is test");
}
private void Btn2_Clicked(object sender, EventArgs e)
{
var myValue = Preferences.Get("key1","");
}
More detailed info about Xamarin.Essentials: Preferences, please take a look the following article:
https://learn.microsoft.com/en-us/xamarin/essentials/preferences?tabs=android
https://www.c-sharpcorner.com/article/xamarin-forms-application-preferences-using-xamarin-essentials/
Update:
If you want to save everything in Preferences, I suggest you can Serialization the data you want to save and deserialization the data that you want to get using Newtonsoft.Json.
Firstly, install Newtonsoft.Json by Nuget package, then do this:
public partial class Page13 : ContentPage
{
public List<person> persons { get; set; }
public Page13()
{
InitializeComponent();
persons = new List<person>()
{
new person(){username="cherry",age=12},
new person(){username="barry",age=14}
};
}
private void Btn1_Clicked(object sender, EventArgs e)
{
string list = Newtonsoft.Json.JsonConvert.SerializeObject(persons);
Preferences.Set("key1", list);
}
private void Btn2_Clicked(object sender, EventArgs e)
{
var myValue = Newtonsoft.Json.JsonConvert.DeserializeObject<List<person>>(Preferences.Get("key1", "")) ;
}
}
public class person
{
public string username { get; set; }
public int age { get; set; }
}
I use List to do example, but you can Serialization evertthing object to string, then save this string in Preference, deserialization string in to object to get data.
So I was not able to find a built in way to do this. I had to manually write code in my app to go through all my preferences, serialize them and them write the string to disk. Likewise for import I had to take a serialized string, reserialize it and then manually place the values back in my preferences.

Internal Server Error 500 Asp.net WebApi trying to DI with Entity

I am building an ASP.net WebApi, and trying to use Entity alongside. I am following this guide.
Getting Started with ASP.NET Web API 2 (C#)
I am receiving a 500 internal server error using Fiddler. The JSON Exception message states ExceptionMessage=An error occurred when trying to create a controller of type 'LocationsController'. Make sure that the controller has a parameterless public constructor.
Here is the Controller.cs
[RoutePrefix("api/Locations")]
public class LocationsController : ApiController
{
// GET api/<controller>
private IlocationsRepository LocationsRepo;
public LocationsController(IlocationsRepository _repo)
{
if (_repo == null) { throw new ArgumentNullException("_repo"); }
LocationsRepo = _repo;
}
[HttpGet]
[Route("")]
public IEnumerable<Location> GetAll()
{
return LocationsRepo.GetAll();
}
}
I can't use a parameterless public constructor because I need to use the Database Repository that was created for Locations. I verified the issue was with the IlocationsRepository by doing the following.
When I replace the LocationsController constructor with no parameters , and declare a List<Location> within the controller, and use dummy data. I receive a 200 with all the json data correct.
Here is the start of the Global.asax.cs file
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
protected void Session_Start(object sender, EventArgs e)
{
}
}
It seems as if I need to do the dependency injection in the Global, but none of the guides had any information regarding this part.
For posterity here is the ContextDB cs
public class WebServerContext : DbContext
{
public WebServerContext() : base("WebServerContext") {}
public DbSet<Order> dOrders { get; set; }
public DbSet<Location> dLocations { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
For additional posterity, here is the Locations Repository.
public class LocationsRepository : IlocationsRepository
{
private z_Data.WebServerContext db = new z_Data.WebServerContext();
public void Add(Location item)
{
db.dLocations.Add(item);
}
public IEnumerable<Location> GetAll()
{
return db.dLocations;
}
}
As per Dependency Injection for Web Api tutorial on MSDN, you are missing the line to register the dependency resolver (a concrete class that implements System.Web.Http.IDependencyResolver) with Web Api. It acts like a bridge between your DI container and Web Api so it can resolve your constructor dependencies.
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container); // <- You need this
// Other Web API configuration not shown.
}
Of course, that assumes you are using Unity. If not, you should either use the DependencyResolver that came with your DI container or implement your own.
NOTE: With some DI containers, you also need to register all of your controllers explicitly.

Serialising and deserialising a JSON object returned by an ASP.Net web service

I have a simple ASP.Net web service / script method that returns a JSON object which is then modified and send back to the page during post back - I need to be able to deserialise this object:
public class MyWebPage : Page
{
[WebMethod]
[ScriptMethod]
public static MyClass MyWebMethod()
{
// Example implementation of my web method
return new MyClass()
{
MyString = "Hello World",
MyInt = 42,
};
}
protected void myButton_OnClick(object sender, EventArgs e)
{
// I need to replace this with some real code
MyClass obj = JSONDeserialise(this.myHiddenField.Value);
}
}
// Note that MyClass is contained within a different assembly
[Serializable]
public class MyClass : IXmlSerializable, ISerializable
{
public string MyString { get; set; }
public int MyInt { get; set; }
// IXmlSerializable and ISerializable implementations not shown
}
I can make changes to both the web method MyWebMethod, and also to a certain extent MyClass, however MyClass needs to implemnt both IXmlSerializable and ISerializable, and is contained within a separate assembly - I mention this because these have caused problems for me so far.
How can I do this? (either using standard .Net types or using something like JSON.Net)
You can use JavaScriptSerializer class from System.Web.Extensions to deserialize JSON string. For example, the following code converts hash into .NET dictionary object:
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string,int>>("{ a: 1, b: 2 }");
Console.WriteLine(dict["a"]);
Console.WriteLine(dict["b"]);
Console.ReadLine();
}
}
}
Code output is:
1
2
JavaScriptSerializer is the class that static page methods use to serialize their responses, so it's also what's appropriate for deserializing that particular JSON:
protected void myButton_OnClick(object sender, EventArgs e)
{
string json = myHiddleField.Value;
MyClass obj = new JavaScriptSerializer().Deserialize<MyClass>(json);
}

How do I feed the language culture thread into the helper class

With asp.net MVC 2, I have been trying to get Matt Hawley's Localization helper to work in my web application, but I am getting stuck feeding a null into the Language string variable. I can't figure out why I am doing this.
namespace MvcLocalization
{
public abstract class LocalizedControllerBase : Controller
{
public String LanguageCode { get; private set; }
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
LanguageCode = requestContext.RouteData.Values["languageCode"].ToString();
if ( !AppConfig.SupportedLanguages.Contains(LanguageCode) )
LanguageCode = AppConfig.DefaultLanguageCode;
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture(LanguageCode);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
base.Execute(requestContext);
}
}
}
What could I be doing wrong?
I figured out how to swap cultures using MIKEBLOG's code in his/her awesome blog post http://helios.ca/2009/05/27/aspnet-mvc-and-localization/
thanks
Paul

Resources