Reflect on an ExpandoObject - reflection

I have written a nifty function that will accept a system.object, reflect on its properties and serialize the object into a JSON string. It looks like this:
public class JSONSerializer
{
public string Serialize(object obj)
Now, I want to be able to do this to serialize a dynamic/ExpandoObject, but because my serializer uses reflection, it isn't able to do it. What's the workaround?
public class Test
{
public dynamic MakeDynamicCat()
{
dynamic newCat = new ExpandoObject();
newCat.Name = "Polly";
newCat.Pedigree = new ExpandoObject();
newCat.Pedigree.Breed = "Whatever";
return newCat;
}
public void SerializeCat()
{
new JSONSerializer().Serialize(MakeDynamicCat());
}
}

I think, this question is very similar: How do I reflect over the members of dynamic object?
At least the answers should help you too.

Related

Remove json field in ASP MVC WebApi Action Method

I have a controller that accepts a model UpdateProductCommand like this:
public IHttpActionResult UpdateProduct(UpdateProductCommand command)
{
command.AuditUserName = this.RequestContext.Principal.Identity.Name;
// ....
}
For security issues, the AuditUserName field should never be set outside (from the API call).
How can I remove (or truncate) the value of this field from JSON request?
It can be achieved by a following ModelBinder:
using Newtonsoft.Json.Linq;
public class FieldRemoverModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
string content = actionContext.Request.Content.ReadAsStringAsync().Result;
JObject json = JObject.Parse(content);
JToken property = json.GetValue(bindingContext.ModelName, StringComparison.OrdinalIgnoreCase);
property?.Parent.Remove();
bindingContext.Model = json.ToObject(bindingContext.ModelType);
return true;
}
}
Use it like this:
public IHttpActionResult UpdateProduct(([ModelBinder(typeof(FieldRemoverModelBinder), Name = nameof(UpdateProductCommand.AuditUserName))]UpdateProductCommand command)
{
// here command.AuditUserName will always be empty, no matter what's in json
That's what DTOs are for.
You can just create another class (UpdateProductCommandDto for example) that has only the properties you need / want to be used as the input, and then you can just use something like Automapper to map it to a new instance of UpdateProductCommand.

ASP.NET. How to modify returned JSON (actionfilter)

We have an ASP.NET application. We cannot edit source code of controllers. But we can implement ActionFilter.
One of our controller action methods returns JSON. Is it possible to modify it in ActionFilter? We need to add one more property to a returned object.
Maybe, some other way to achieve it?
Found this interesting and as #Chris mentioned, though conceptually I knew this would work, I never tried this and hence thought of giving it a shot. I'm not sure whether this is an elegant/correct way of doing it, but this worked for me. (I'm trying to add Age property dynamically using ActionResult)
[PropertyInjector("Age", 12)]
public ActionResult Index()
{
return Json(new { Name = "Hello World" }, JsonRequestBehavior.AllowGet);
}
And the filter:
public class PropertyInjector : ActionFilterAttribute
{
string key;
object value;
public PropertyInjector(string key, object value)
{
this.key = key;
this.value = value;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var jsonData = ((JsonResult)filterContext.Result).Data;
JObject data = JObject.FromObject(jsonData);
data.Add(this.key,JToken.FromObject(this.value));
filterContext.Result = new ContentResult { Content = data.ToString(), ContentType = "application/json" };
base.OnActionExecuted(filterContext);
}
}
Update
If it's not dynamic data which is to be injected, then remove filter constructor and hard code key & value directly and then the filter could be registered globally without editing the controller
GlobalFilters.Filters.Add(new PropertyInjector());

Asp.Net Web Api - attribute for not binding/formatting a parameter?

I have a method on an ApiController that looks like this:
public IEnumerable<Items> GetSlideSets() {
IServiceClass serviceClass = new ServiceClass();
//...
Yes, I am aware that this is not good design but I'm addressing this issue in a different iteration.
At a certain point in my application I need to call this functionality from within the project itself so I thought I could simply reuse the controller (and why not, I can pluck it out of my IoC container). The only problem is that in this case, I need to inject my own implementation of IServiceClass, easy enough:
public IEnumerable<Items> GetSlideSets(IServiceClass serviceClass = null) {
serviceClass = serviceClass ?? new ServiceClass();
//...
Except now I am getting errors when calling this via a regular Api call Optionalparameter 'serviceClass' is not supported by FormatterParameterBinding.
I know that there are various attributes that control bindings. Is there one that I can put on the parameter to say it shouldn't bind.
Like others have mentioned, it's probably a better idea to inject the dependency in the constructor.
But if you really must avoid binding an action parameter, there isn't a built-in attribute but you can create one pretty easily. Here's what it could look like:
public class DontBindAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
return new DontBindParameterBinding(parameter);
}
private class DontBindParameterBinding : HttpParameterBinding
{
public DontBindParameterBinding(HttpParameterDescriptor parameter) : base(parameter)
{
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
actionContext.ActionArguments.Add(Descriptor.ParameterName, Descriptor.DefaultValue);
var completedTaskSource = new TaskCompletionSource<object>();
completedTaskSource.SetResult(null);
return completedTaskSource.Task;
}
}
}
You just need to apply the attribute to the parameter afterwards:
public IEnumerable<Items> GetSlideSets([DontBind] IServiceClass serviceClass = null)

is it a good idea to create an enum for the key names of session values?

instead of doing
session("myvar1") = something
session("myvar2") = something
session("myvar3") = something
session("myvar4") = something
is doing
enum sessionVar
myvar1
myvar2
myvar3
myvar4
end enum
session(sessionVar.myvar1.tostring) = something
session(sessionVar.myvar2.tostring) = something
session(sessionVar.myvar3.tostring) = something
session(sessionVar.myvar4.tostring) = something
would be better?
Instead of using constants for the session keys, I'm using my own type-safe session object, which looks like this (sorry this is in C#, see below for a VB version):
public class MySession
{
// Private constructor (use MySession.Current to access the current instance).
private MySession() {}
// Gets the current session.
public static MySession Current
{
get
{
MySession session = HttpContext.Current.Session["__MySession__"] as MySession;
if (session == null)
{
session = new MySession();
HttpContext.Current.Session["__MySession__"] = session;
}
return session;
}
}
// My session data goes here:
public string MyString { get; set; };
public bool MyFlag { get; set; };
public int MyNumber { get; set; };
}
Whenever I need to read/write something to/from the session, I can use my typesafe session object like this:
string s = MySession.Current.MyString;
s = "new value";
MySession.Current.MyString = s;
This solution results in several advantages:
I have a typesafe Session (no more type-casts)
I can document all session based data (by commenting the public properties in MySession)
When adding a new element to the session, I don't have to search the solution to check if the same session-key was already used somewhere else.
Update:
Here's a VB version (automatically converted from the C# version). Sorry, but I don't know VB and so I didn't know how to write the properties in VB:
Public Class MySession
' Private constructor (use MySession.Current to access the current instance).
Private Sub New()
End Sub
' Gets the current session.
Public Shared ReadOnly Property Current() As MySession
Get
Dim session As MySession = TryCast(HttpContext.Current.Session("__MySession__"), MySession)
If session = Nothing Then
session = New MySession()
HttpContext.Current.Session("__MySession__") = session
End If
Return session
End Get
End Property
' My session data goes here:
Public MyString As String
Public MyFlag As Boolean
Public MyNumber As Integer
End Class
Only if those values are related. Otherwise use plain old constants.
How about:-
public static class SessionVar
{
public static readonly string myVar1 = "myVar1";
public static readonly string myVar2 = "myVar2";
public static readonly string myVar3 = "myVar3";
public static readonly string myVar4 = "myVar4";
}
This allows you to use:-
session(SessionVar.myVar1) = something;
I've used classes like this to make a typed session/cache wrapper. You may need to add additional code to the get/set, but I'll leave that up to you.
internal class SessionHelper
{
private const string myVar1Key = "myvar1";
public static int MyVar1
{
get
{
return (int)System.Web.HttpContext.Current.Session[myVar1Key];
}
set
{
System.Web.HttpContext.Current.Session[myVar1Key] = value;
}
}
}
Sorry about the C#....
For the simple thing of removing all of the string key references, I would go with global static/shared constants visible at application scope.
Otherwise, the strongly typed simple wrapper for session variables is a superior alternative, and it's far more OOP-friendly considering that you get intellisense and Object Browser compatibility.
The only way I can see the enum being of much value is to be used to index into an array or a similar list. But even then you have to cast the enum to an int.
So, you could have an array that you load at application startup with all of your session variable keys and then an enum for the indexes. However, given that the Session object derives from HttpSessionState, which derives from IEnumerable, you should be able to just do a foreach loop over the session variables, if you need to.
I realize this question was asked a while ago and an "answer" has already been picked. But I just came across it. Martin's answer is good. However, to assist anyone who stumbles across this in the future, if you really want a slick way to deal with Session, read this post. I don't think you'll find anything easier.
I came up with a solution that avoids certain disadvantages of the other solutions posted by keeping the structure of the Session variables intact. It is simply a type-safe shortcut to get and set Session variables.
It's C#, but I posted some auto-generated VB.NET at the end.
The best solutions I have seen (the accepted answer and the one by TheObjectGuy) require a custom class that is stored in a Session variable, and then is pulled from the Session to access its properties with something like MySessionClass.Current.MyProperty.
The problem with this is that if you are currently using (or may use in the future) something other than an InProc Session-State mode (see https://msdn.microsoft.com/en-us/library/ms178586%28v=vs.140%29.aspx), the whole class would have to go through serialization to access a single property.
Also, that means you lose the IEnumerable and ICollection implementations offered by the actual Session, if you need those. With my solution, you can simply access the actual Session if you need this functionality.
You can easily use these session variables and they are type-safe. It can be used alongside statements like Session["MyProperty"], which will allow for conversion of an existing project one reference at a time. So:
int myInt = (int)Session["MyInt"];
Session["MyInt"] = 3;
becomes:
int myInt = SessionVars.MyInt;
SessionVars.MyInt = 3;
Here is the actual class. The CallerMemberName requires .NET 4.5, but even if you are using an older version you could still manage it by explicitly passing the propertyName. Also, the types of the properties must be nullable to make it act exactly the same as standard Session["MyProp"] calls because a non-set
public static class SessionVars
{
private static T Get2<T>([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (HttpContext.Current.Session[propertyName] == null)
{
return default(T);
}
return (T)HttpContext.Current.Session[propertyName];
}
private static void Set2<T>(T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
HttpContext.Current.Session[propertyName] = value;
}
public static int MyInt { get { return Get2<int>(); } set { Set2<int>(value); } }
public static bool MyBool { get { return Get2<bool>(); } set { Set2<bool>(value); } }
public static string MyString { get { return Get2<string>(); } set { Set2<string>(value); } }
}
I even wrote a code snippet to facilitate adding these properties:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<Header>
<Title>SessionVars Property</Title>
<Author>kevinpo</Author>
<Shortcut>sv</Shortcut>
<Description>Adds a property for use in a SessionVars class</Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<Default>PropertyName</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[public static $type$ $property$ { get { return Get2<$type$>(); } set { Set2<$type$>(value); } }]]>
</Code>
</Snippet>
</CodeSnippet>
I'm a C# guy, so this VB.NET is just auto-converted by http://converter.telerik.com/:
Public NotInheritable Class SessionVars
Private Sub New()
End Sub
Private Shared Function Get2(Of T)(<System.Runtime.CompilerServices.CallerMemberName> Optional propertyName As String = "") As T
If HttpContext.Current.Session(propertyName) Is Nothing Then
Return Nothing
End If
Return DirectCast(HttpContext.Current.Session(propertyName), T)
End Function
Private Shared Sub Set2(Of T)(value As T, <System.Runtime.CompilerServices.CallerMemberName> Optional propertyName As String = "")
HttpContext.Current.Session(propertyName) = value
End Sub
Public Shared Property MyInt() As Integer
Get
Return Get2(Of Integer)()
End Get
Set
Set2(Of Integer)(value)
End Set
End Property
Public Shared Property MyBool() As Boolean
Get
Return Get2(Of Boolean)()
End Get
Set
Set2(Of Boolean)(value)
End Set
End Property
Public Shared Property MyString() As String
Get
Return Get2(Of String)()
End Get
Set
Set2(Of String)(value)
End Set
End Property
End Class
'=======================================================
'Service provided by Telerik (www.telerik.com)
'Conversion powered by NRefactory.
'Twitter: #telerik
'Facebook: facebook.com/telerik
'=======================================================

Can't Deserialize a Nullable KeyValuePair from JSON with ASP.NET AJAX

The following class does not deserialize (but does serialize) using System.Web.Script.Serialization.JavaScriptSerializer.
public class foo {
public KeyValuePair<string, string>? bar {get;set;}
}
The attempt to deserialize results in a System.NullReferenceException when System.Web.Script.Serialization.ObjectConverter.ConvertDictionaryToObject reaches the bar property. (Note, that is a surmise based on the stack trace.)
Changing the property type to KeyValuePair<string,string> fixes the problem, but I'd like to keep the Nullable type if at all possible.
The JSON is exactly what you would expect:
{"foo": {
"bar": {
"Key":"Jean-Luc",
"Value":"Picard"
}
}}
Help?
The reason this happens is that when the JavaScriptSerializer tries to deserialize it will create a new instance of the class (in this the KeyValuePair) and then assign the values to properties.
This causes an issue as the KeyValuePair can only have the key and values assigned as part of the constructor and not via properties so results in an empty key and value.
You will be able to resolve this and the null issue by creating a class that implements JavaScriptConverter and Registering It. I have used the code below to handle a standard KeyValuePair but I am sure you can extend it to handle nulls.
public class DictionaryJavaScriptConverter<k, v> : JavaScriptConverter
{
public override object Deserialize(System.Collections.Generic.IDictionary<string, object> dictionary, System.Type type, System.Web.Script.Serialization.JavaScriptSerializer serializer)
{
return new KeyValuePair<k, v>((k)dictionary["Key"], (v)dictionary["Value"]);
}
public override System.Collections.Generic.IDictionary<string, object> Serialize(object obj, System.Web.Script.Serialization.JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override System.Collections.Generic.IEnumerable<System.Type> SupportedTypes {
get { return new System.Type[] { typeof(KeyValuePair<k, v>) }; }
}
}
Alternately you can create a simple class that has two properties key and value.
You can have a look at this wrapper:
http://www.codeproject.com/KB/aspnet/Univar.aspx
I've successfully Json serialized and deserialized the nullable KeyValue pair using it.

Resources