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

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);
}

Related

Xamarin Forms overriding OnAppearing causes app to crash

I am trying to do a simple override and load some data when my page loads, I am using the following code in the code behind page.
namespace XYZ
{
public partial class MainPage : ContentPage
{
private Label results;
private Label groupResults;
public MainPage()
{
InitializeComponent();
results = new Label();
groupResults = new Label();
}
protected override void OnAppearing()
{
base.OnAppearing();
storeIdTxt.Text = Settings.StoreIdSetting;
}
}
}
If I uncomment the override things works just fine, the error I am getting seems to be a generic one attached here
my settings class is fairly simple as follows
using System;
using System.Collections.Generic;
using System.Text;
using Plugin.Settings;
using Plugin.Settings.Abstractions;
namespace NWMPosNG.Helpers
{
/// <summary>
/// This is the Settings static class that can be used in your Core solution or in any
/// of your client applications. All settings are laid out the same exact way with getters
/// and setters.
/// </summary>
public static class Settings
{
private static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
private const string SettingsKey = "settings_key";
private static readonly string SettingsDefault = string.Empty;
private const string StoreId = null;
private static readonly string StoreIdDefault = "0";
#endregion
public static string GeneralSettings
{
get
{
return AppSettings.GetValueOrDefault(SettingsKey, SettingsDefault);
}
set
{
AppSettings.AddOrUpdateValue(SettingsKey, value);
}
}
public static string StoreIdSetting
{
get
{
return AppSettings.GetValueOrDefault(StoreId, StoreIdDefault);
}
set
{
AppSettings.AddOrUpdateValue(StoreId, value);
}
}
}
}
I narrowed down the issue to when I access the saved data using
storeIdTxt.Text = Settings.StoreIdSetting;
But I don't understand why that causes the crash.
You are using the Settings Plugin from James Montemagno. Which is pretty much a KeyValuePair that is stored on the local device across sessions.
In your case:
AppSettings.GetValueOrDefault(StoreId, StoreIdDefault);
Translates to:
AppSettings.GetValueOrDefault(null, "0");
Which crashes because 'null' can't be a key. That's why setting the key (StoreId) prevents the crash from happening.
This line was the culprit
private const string StoreId = null;
I don't really understand why but setting this to a non NULL value makes the crash go away

How to make ASP.NET to stop interpret null as string

I have a Web API method:
public List<Task> GetTasks([FromUri] TaskFilter filter)
{
}
The method has parameter with list of nullable identifiers:
public class TaskFilter
{
public IList<int?> Assignees { get; set; }
}
When I call it:
GET /tasks?assignees=null
Server returns an error:
{
"message":"The request is invalid.",
"modelState": {
"assignees": [ "The value 'null' is not valid for Nullable`1." ]
}
}
It works only if I pass empty string:
GET /tasks?assignees=
But standard query string converters (from JQuery, Angular, etc) do not work with nulls in such way.
How to make ASP.NET to interpret 'null' as null?
Upd: The query string can contain several identifiers, e.g.:
GET /tasks?assignees=1&assignees=2&assignees=null
Upd2: JQuery converts nulls in array to empty strings, and ASP.NET interprets them as null. So the question is about calling WebAPI from Angular 1.6 ($HttpParamSerializerProvider)
Upd3: I know about workarounds, but I do not ask for them. I want a solution for specific problem:
It is a GET method
Method accepts a list from Uri
A list can contain null values
It should be List<int?> because API docs are generated automatically, and I do not want to see text array as parameter type
By default ASP.NET expects empty strings for null values (JQuery.param works in that way)
But some client libraries (e.g. Angular) does not convert null array items to empty strings
You can create a custom model bind for this specific type, inherithing from DefaultModelBinder, for sample:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
public class TaskFilterBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var assignees = request.QueryString["assignees"];
if (assignees == "null") // check if assignees is null (string) then return NULL
return null;
return assignees;
}
}
Finally we need to inform the controller as to the binding we want it to use. This we can specify using attributes
[ModelBinder(typeof(TaskFilterBinder))]
as below:
public List<Task> GetTasks([FromUri(ModelBinder=typeof(TaskFilterBinder))] TaskFilter filter)
{
// Do your stuff.
}
For more reference check this link on Custom Model Binders.
Hope, this solves your problem . Thanks
Finally, I found a solution using custom value provider:
using System;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ValueProviders;
using System.Web.Http.ValueProviders.Providers;
using System.Globalization;
using System.Net.Http;
using System.Web.Http.ModelBinding;
public sealed class NullableValueProviderAttribute : ModelBinderAttribute
{
private readonly string[] _nullableColumns;
public NullableValueProviderAttribute(params string[] nullableColumns)
{
_nullableColumns = nullableColumns;
}
public override IEnumerable<ValueProviderFactory> GetValueProviderFactories(HttpConfiguration configuration)
{
return new ValueProviderFactory[] { new NullableValueProviderFactory(_nullableColumns) };
}
}
public class NullableValueProviderFactory : ValueProviderFactory, IUriValueProviderFactory
{
private readonly string[] _nullableColumns;
public NullableValueProviderFactory(string[] nullableColumns)
{
_nullableColumns = nullableColumns;
}
public override IValueProvider GetValueProvider(HttpActionContext actionContext)
{
return new NullableQueryStringValueProvider(actionContext, CultureInfo.InvariantCulture, _nullableColumns);
}
}
public class NullableQueryStringValueProvider : NameValuePairsValueProvider
{
private static readonly string[] _nullValues = new string[] { "null", "undefined" };
private static IEnumerable<KeyValuePair<string, string>> GetQueryNameValuePairs(HttpRequestMessage request, string[] nullableColumns)
{
foreach (var pair in request.GetQueryNameValuePairs())
{
var isNull = Array.IndexOf(nullableColumns, pair.Key) >= 0 && Array.IndexOf(_nullValues, pair.Value) >= 0;
yield return isNull ? new KeyValuePair<string, string>(pair.Key, "") : pair;
};
}
public NullableQueryStringValueProvider(HttpActionContext actionContext, CultureInfo culture, string[] nullableColumns) :
base(GetQueryNameValuePairs(actionContext.ControllerContext.Request, nullableColumns), culture)
{ }
}
And specify it in Web API action:
public List<Task> GetTasks([NullableValueProvider("assignees")] TaskFilter filter)
{
}

Change default session provider in ASP.NET

I want to change my session proviced to statically typed - I just hate typing strings because of many many errors I do.
What technology am I using? ASP.NET MVC via EXT.NET MVC
I was trying to do that using web.config but the problem is that after add session state to it visual is not going to compile my code because of that session should be using strings as keys.
I want to use session by enums such as :
public enum SessionEnum{Model}
public class Bar{
void foo(){
Session[SessionEnum.Model] = "blah";
}
}
I am aware that I can create wrapper converting enums to strings but it's not very satisfying solution for me.
public class StorageWrapper{
public object this[SessionEnum enum]{ get{return Session[enum.toString()]}; //+set
}
What I did was create static object for base class for all of my controllers and then I was able to use it across them but after closing and opening the page again I wasn't able to get values from it. I guess I should serialize them somehow but I have no idea how.
Is there any way to do that?
EDIT
My session now looks like this :
[Serializable]
public abstract class DataWrapper<T> : HttpSessionStateBase
{
Dictionary<T, object> Dictionary { get; set; } = new Dictionary<T, object>();
public object this[T a]
{
get
{
try
{
return Dictionary[a];
}
catch
{
return null;
}
}
set { Dictionary[a] = value; }
}
}
[Serializable]
public class SessionWrapper : DataWrapper<SessionNames>
{}
public enum SessionNames { Model, Login, LastOpenedFile }
It's very simple.
Create a UserSession object which does everything you want (holds your values as enum etc), instantiate it, then put it in the session.
var US = new UserSession();
US.stuff = somestuff;
Session["UserSess"] = US
Then you can just always use Session["UserSess"].stuff;
Mmmm, wouldn't you use static const string instead of an enum?
using System.Web;
public static class SessionEnum
{
public static const string Model = "_Session_Model";
public static const string Login = "_Session_Login";
public static const string LastOpenedFile = "_Session_LastOpenedFile ";
}
class test
{
void test()
{
Session[SessionEnum.Model] = "blah";
}
}

ASP.NET is System.Web.UI.Page thread safe

I am wondering if the following code is thread safe?
Can i be be sure that UniqueFoo will indeed be the Unique Foo and will not be override?
public partial class Dummy : System.Web.UI.Page
{
public string UniqueFoo{ get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var id = int.Parse(Request["Id"]);
UniqueFoo = SomeThreadSafeWCF.GetUniqueFoo(id);
}
}
what about the following (static)
public partial class Dummy : System.Web.UI.Page
{
public static string UniqueFoo{ get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var id = int.Parse(Request["Id"]);
UniqueFoo = SomeThreadSafeWCF.GetUniqueFoo(id);
}
}
i later want to use UniqueFoo in a [WebMethod]
[WebMethod]
public static void SetSomeObject(SetSomeObject obj)
{
SomeThreadSafeWCF service = new SomeThreadSafeWCF ();
service.SetSomeObject(UniqueFoo, obj);
}
EDIT:
I am getting SetSomeObject from JS and UniqueFoo is coming from ASP.NET
will i have any issues when NOT using the static in my Dummy class according to your answers?
Surely your first sample is thread safe because when a request of a page post to the Web Server asp.net make new instance of your page and call page_load so if your SomeThreadSafeWCF.GetUniqueFoo() always make a unique Foo everything is thread save
Your second code snippet is not thread safe because you are modifying the value of a static field. So for example if later in this page you attempt to read the value of this UniqueFoo field you might not get the value you expect.
The first code snippet is fine because the field is not static.
If you want to use the UniqueFoo in a WebMethod then I would recommend you to pass it to this web method when calling it.
[WebMethod]
public static void SetSomeObject(SetSomeObject obj, string uniqueFoo)
{
SomeThreadSafeWCF service = new SomeThreadSafeWCF ();
service.SetSomeObject(uniqueFoo, obj);
}

Mocking a protected generic method with Moq

To mock a protected virtual (non-generic) method in Moq is easy:
public class MyClass
{
....
protected virtual int MyMethod(Data data){..}
}
And to mock it:
myMock.Protected().Setup<int>("MyMethod", ItExpr.Is<Data>( ...
I could not find a way to use the same technique if the protected method is generic, like:
protected virtual int MyMethod<T>(T data)
Any idea how to do it, besides using a wrapper class to override that method, is highly appreciated.
I've checked the source and it seems mocking protected generic methods with Moq is not supported:
The Protected() method creates an instance of a class ProtectedMock<T> which uses the following method to get the method that you want to mock:
private static MethodInfo GetMethod(string methodName, params object[] args)
{
return typeof(T).GetMethod(
methodName,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
null,
ToArgTypes(args),
null);
}
It uses Type.GetMethod to get the method for mocking, but GetMethod (although MSDN states differently) don't play nice with generics, see:
GetMethod for generic method
Get a generic method without using GetMethods
Side note:
In my opinion mocking a protected member is a code smell, and I would rather try to avoid it anyway with refactoring my design (beside that it's not supported in Moq).
It can be done since Moq 4.13 (2019-09-01) by using As for protected methods and It.IsAnyType for generic type arguments:
classUnderTest.Protected().As<IMyMethodMock>().Setup(x => x.MyMethod(It.IsAny<It.IsAnyType>())).Returns(...);
And create the following interface for the mocking method:
public interface IMyMethodMock
{
int MyMethod<T>(T data);
}
Full example:
[TestClass]
public class MockingProtectedGenericFixture
{
[TestMethod]
public void test()
{
// Arrange
var classUnderTest = new Mock<MyClass>();
classUnderTest.Protected().As<IMyMethodMock>().Setup(x => x.MyMethod(It.IsAny<It.IsAnyType>())).Returns(2);
// Act
var resForStringData = classUnderTest.Object.GetNumber("DataString");
var resForBooleanData = classUnderTest.Object.GetNumber(true);
// Assert
Assert.AreEqual(2, resForStringData);
Assert.AreEqual(2, resForBooleanData);
}
}
public class MyClass
{
public int GetNumber<T>(T data)
{
return MyMethod(data);
}
protected virtual int MyMethod<T>(T data)
{
return 1;
}
}
public interface IMyMethodMock
{
int MyMethod<T>(T data);
}

Resources