Why do class fields get defaulted at deserialization? - .net-core

Hello i am having a class that is defined in a .Net Standard assembly.
Now i have a reference to that assembly from my .Net Core project.
When i try to deserialize the class in my .Net Core my class fields are default.
By default i mean value types get all inner values default and class fields are null.
In my example if Val is an int it would have its value 0 after deserialization whereas would it have been a class it would be null.
.NET Standard class
public class Matrix
{
public int Val { get; set; }
public Matrix(int set) //value is default
{
this.Val = set;
}
}
.NET Core
static void Main(string[] args)
{
Matrix matr = new Matrix(3);
var str=JsonConvert.SerializeObject(matr);
var bytes=Encoding.Utf8.GetBytes(str);
var str = Encoding.UTF8.GetString(bytes); //string looks ok !
var deser = JsonConvert.DeserializeObject<Matrix>(str);
}
Please note that my class uses a parameter in the constructor.Could this be the problem ? If my parameter constructor is indeed the problem ...how do you manage to serialize an object that needs to perform some logic in its constructor via his parameters ?

Code which you provided works good. After deserialization in deser.Val you will see 3. But if you will change public int Val { get; private set; } or public int Val { get; } you will have a default value. For reference type it will be NULL for value type it depends.
Maybe you can provide more information and screenshot of problem?

Related

OData paging with expand issue

I'm using OData v5/Web API 2.2 to create an endpoint that will return a list of employees from each company.
My problem occurs when I try to implement server-side paging while also using the OData $expand property. When I try to make a call to
http://localhost:60067/Companies?$expand=Employees
I get an error that says "Could not find a property named 'Employees' on type 'System.Web.OData.Query.Expressions.SelectAllAndExpand_1OfCompanyApiModel'"
However, when I removed the EnableQuery attribute the call to the endpoint or when I didn't expand it works as expected. Does anyone have an idea of what I am doing wrong? I've been googling this for a while but haven't found anything.
Here are some code snippets -
Data Models:
public class CompanyApiModel
{
[Key]
public Guid CompanyGuid { get; set; }
[Required]
public string Name { get; set; }
// other properties
public List<EmployeeApiModel> Employees { get; set; }
}
public class EmployeeApiModel
{
[Key]
public Guid EmployeeGuid { get; set; }
[Required]
public string Name { get; set; }
// other properties
}
CompaniesController.cs:
[EnableQuery(PageSize = 10)] // If I comment this out everything works
//[EnableQuery] // This fails as well
public IHttpActionResult Get(ODataQueryOptions<CompanyApiModel> queryOptions)
{
var companies = GetCompanies(queryOptions);
return Ok(companies);
// return Ok(companies.AsQueryable()); // This doesn't work either
}
WebApiConfig.cs:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
var routingConventions = ODataRoutingConventions.CreateDefault();
routingConventions.Insert(0, new OptionsRoutingConvention());
config.MapODataServiceRoute("odata", null, GetEdmModel(), new DefaultODataPathHandler(), routingConventions);
// below code allows endpoints to respond with either XML or JSON, depending on accept header preferences sent from client
// (default in absence of accept header is JSON)
var odataFormatters = ODataMediaTypeFormatters.Create();
config.Formatters.InsertRange(0, odataFormatters);
config.EnsureInitialized();
}
public static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "Demos";
builder.ContainerName = "DefaultContainer";
builder.EntitySet<CompanyApiModel>("Companies");
builder.EntitySet<EmployeeApiModel>("Employees");
var edmModel = builder.GetEdmModel();
return edmModel;
}
}
Figured out the problem. We were overriding the EnableQuery attribute somewhere in our code and calling it EnableMappedQuery and applying it to the controller. Thus instead of having [EnableQuery(PageSize = 10)] I should have had [EnableMappedQuery(PageSize = 10)].
EnableQuery Attribute do many works,
1. it will validate the queryoption for you.
2. it will apply the queryoption for you.
3. it can add some querysettings like PageSize.
Your scenario not working is because your GetCompanies is already applied the queryoption, so when EnableQuery get the result and apply the queryoption again, it fails, it can't find the expand property, my suggestion is just return original Company and let EnableQuery do the reset of work for you, ODataQueryOption in parameter is also not needed.
If you realy do some custom work in GetCompanies and don't need EnableQuery to apply for you, you can add PageSize in ODataQuerySettings when you call method ODataQueryOptions.ApplyTo(IQueryable, ODataQuerySettings).

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 MVC How to avoid static variables?

recently posted about questioning how unsafe static variables are, I've since discovered I need to get rid of them. But I cannot figure out how to? Was thinking a static Get() method for each class, that returns a single instance, but then that instance would have to be declared static.
So the only way to do it, is to have the instance references (for each helper, I.E user helper.cs, imagehelper.cs etc.) is to declare them as instance properties on some sort of globally accessible class? But which class? Is there something I'm missing here?
Code below of a sample class I need to change:
sing System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Mvc.Mailer;
namespace MVCWebsite.Helpers
{
public class AppSettings
{
public static void OnAppInit()
{
//General
AppName = "MyApp";
DesktopBaseURLs = new Dictionary<string, string>();
DesktopBaseURLs.Add("dev", "localhost:50560");
DesktopBaseURLs.Add("test", "www.test.whatever.com");
DesktopBaseURLs.Add("live", "www.whatever.com");
MobileBaseURLs = new Dictionary<string, string>();
MobileBaseURLs.Add("dev", "m.local.whatever.com");
MobileBaseURLs.Add("test", "m.test.whatever.com");
MobileBaseURLs.Add("live", "m.whatever.com");
//Emails
EmailHostName = AppName + ".com"; //For the moment atleast
NoReplyEmailAddress = "no-reply#" + EmailHostName.ToLower();
SupportEmailAddress = "support#" + EmailHostName.ToLower();
ErrorEmailAddress = "errors#" + EmailHostName.ToLower();
//Resources
TempFileURL = "/content/temp/";
UserDataURL = "/content/user-content/";
ProfilePicturesURL = UserDataURL + "profile-pictures/";
var a = GlobalHelper.GetURLAsServerPath(ProfilePicturesURL);
var b = a;
}
//General
public static string AppName { get; set; }
public static Dictionary<string, string> DesktopBaseURLs;
public static Dictionary<string, string> MobileBaseURLs;
//Emails
public static string EmailHostName { get; set; }
public static string NoReplyEmailAddress { get; set; }
public static string SupportEmailAddress { get; set; }
public static string ErrorEmailAddress { get; set; }
//Resources
public static string UserDataURL { get; set; }
public static string TempFileURL { get; set; }
public static string ProfilePicturesURL { get; set; }
//Methods
public static void SetAppURL()
{
}
}
}
I recommend creating an interface for your AppSettings class, so that you can use it in your controllers now, and implement it in different ways as you see fit:
public interface IAppSettings
{
string AppName { get; set; }
...
}
You can then implement it immediately with your static class via a wrapper class:
public class AppSettingsWrapper : IAppSettings
{
public AppName
{
get
{
return AppSettings.AppName;
}
set
{
AppSettings.AppName = value;
}
}
...
}
Later on, you can create an implementation of IAppSettings that uses session, or cookies, or database values, or whatever. The important thing is to abstract the way you store things so that you can implement in a way that meets your needs.
The answer to you previous question clearly stated that the IDictionary was the only unsafe variable in your static method because it's not thread safe. You just need to store these variables differently. You don't need to get rid of all of your static variables. You just need to change IDictionary to something thread safe.
By the way, someone there makes a good coment about web.config
Right I think I've figured it out, they should be stored as instance variables within Global.asax.cs. This file contains your Application class which inherits from System.Web.HttpApplication. This master class is limited to one instance (of itself) per request. So if you store any references to your helpers here, you can reference them by going, MvcApplication.MyHelper.DoSomething(); Someone please correct me if this is wrong, but seems right to me. "At any single point of time, an HTTPApplication instance handles only one request, so we don't need to think about locking and unlocking of any non static members, but for static members we do require. " -from : http://www.codeproject.com/Articles/87316/A-walkthrough-to-Application-State#c

Creating an EF CodeFirst DbContext using Roslyn

Just a little idea I'm playing with, not sure if it's viable or has much of a use.
I'm trying to generate a very basic EF Code First database using the Roslyn CTP.
Code:
var scriptEngine = new ScriptEngine(new[] { "System", "System.Core", typeof(DbContext).Assembly.Location });
var session = Roslyn.Scripting.Session.Create();
var t = scriptEngine.CompileSubmission<DbContext>(#"
using System.Data.Entity;
public class Car {
public int Id {get; set;}
public string Name {get; set; }
}
public class Context : DbContext {
public DbSet<Car> Cars {get; set; }
}
new Context();
", session);
t.Execute();
When executed I get the following exception
Exception:
The type 'Submission#0+Car' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive, nested or generic, and does not inherit from EntityObject.
Looking through the list of possible issues, I'm guessing that Roslyn is making a nested class as part of the code gen. This makes sense otherwise the "new Context();" call would need to be wrapped into a class/method of some sort. I could emit an assembly, which would confirm the above but likely wouldn't have any clues on how to write it correctly.
I also went down the route of Syntax.ClassDeclaration, but ended up with a few hundred lines of code just to make a class with 1 property and no obvious way how to instantiate that class.
Question
Is there an easy way to create a class in Roslyn that is publicly accessible (eg not nested in another class)?
You can use Roslyn to create actual DLL library that contains your type based on your source code and then use that from your script:
var classCode = #"
using System.Data.Entity;
public class Car {
public int Id { get; set; }
public string Name { get; set; }
}
public class Context : DbContext {
public DbSet<Car> Cars { get; set; }
}";
var syntaxTree = SyntaxTree.ParseCompilationUnit(classCode);
var compilation = Compilation.Create(
"car",
new CompilationOptions(assemblyKind: AssemblyKind.DynamicallyLinkedLibrary))
.AddReferences(
new AssemblyFileReference(typeof(object).Assembly.Location), // mscorlib
new AssemblyFileReference(typeof(Uri).Assembly.Location), // System
new AssemblyFileReference(typeof(IOrderedQueryable<>).Assembly.Location), // System.Data
new AssemblyFileReference(typeof(DbContext).Assembly.Location) // EntityFramework
)
.AddSyntaxTrees(syntaxTree);
var dllPath = "car.dll";
using (var stream = File.OpenWrite(dllPath))
{
compilation.Emit(stream);
}
var code = #"new Context();";
var scriptEngine = new ScriptEngine(new[] { new FileInfo(dllPath).FullName, "EntityFramework" });
var context = scriptEngine.Execute<DbContext>(code);

C# Optional Object Action MVC Parameter

Is it possible to specify an object as a parameter in MVC with default values in some way?
E.g.
public virtual ViewResult Index(RequirementFilters requirementFilters)
I'd like to initialize the values of a couple of parameters on RequirementFilters?
At the moment I am doing
public virtual ViewResult Index(int status=1, bool required =false)
I wanted to create a Filter Object so I could re-use it but I can't figure out way of setting defaults for the object in the Action Parameters.
Thanks
Graeme
You could create a custom ActionFilter attribute and create an instance of your Filter Object there. You can provide some properties through the custom attribute.
Here's an example:
public class DefaultQuerySettingsAttribute : ActionFilterAttribute
{
public string ParameterName { get; set; }
public Type SettingsType { get; set; }
public int Rows { get; set; }
public string SortColumn { get; set; }
public string SortOrder { get; set; }
public bool PagingEnabled { get; set; }
public DefaultQuerySettingsAttribute()
{
this.ParameterName = "settings";
var defaultSettings = new QuerySettings();
this.Rows = defaultSettings.Rows;
this.SortColumn = defaultSettings.SortColumn;
this.SortOrder = defaultSettings.SortOrder;
this.PagingEnabled = defaultSettings.PagingEnabled;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (filterContext.ActionParameters.ContainsKey(this.ParameterName))
{
var querySettings = filterContext.ActionParameters[this.ParameterName] as QuerySettings;
if (querySettings == null || string.IsNullOrWhiteSpace(querySettings.SortColumn))
filterContext.ActionParameters[this.ParameterName] = this.GetQuerySettings();
}
}
private QuerySettings GetQuerySettings()
{
var querySettings = (QuerySettings)Activator.CreateInstance(SettingsType ?? typeof(QuerySettings));
querySettings.Rows = Rows;
querySettings.SortColumn = SortColumn;
querySettings.SortOrder = SortOrder;
querySettings.PagingEnabled = PagingEnabled;
return querySettings;
}
}
ParameterName is the name of the argument in the action method (requirementFilters in your case).
You can also specify actual type that will be instantiated by providing SettingsType.
Users sometimes prefer to see the defaults on screen, rather than allowing the system to hide the defaults internally.
A better way of having defaults will be to actually show the defaults on int UI, in the HTML by rendering it with together with the defaults. That way when someone posts the page, the defaults which you pre-rendered is also posted and binded to the model.
So try and see if you can render with defaults whatever for you are rendering and posted to the Index action.
Finally, if you can't do it that way, what is preventing you from initializing the properties with default values in the no-arg constructor while creating the object?
EDIT
Or you can use the C# language feature the null coalescent operator to implement defaults. Look here to read about it.
As long as you don't need to change the defaults per action, you can set them in the default constructor of the Model.

Resources