SmartFormat best way to serialize a dictionary - dictionary

I have a data object with an dictionary.
Now I want to serialize this dictionary to a json string.
Is it possible to do this inside the template?
public string GenerateTest()
{
Dictionary<string, object> dataDictionary = new Dictionary<string, object>();
dataDictionary.Add("Testdata1", "Value1");
dataDictionary.Add("Testdata2", "Value2");
string result = Smart.Format(CultureInfo.InvariantCulture, "{data.someFormattertoGetAnJsonString}", new {data= dataDictionary });
Console.WriteLine(result);
return result;
}

Sure you could do that, but not in a generic way. SmartFormat is a formatter, rather than a serializer. So in general, SmartFormat is best in filling a text template with data, like it is required with mail merge.
In your case, you'll be better off using serializers like System.Text.Json or Newtonsoft.Json.
For the latter, here is an example how simple this works: https://www.newtonsoft.com/json/help/html/serializedictionary.htm

I have attached my solution. You have to register the ToJSONFormatter with the AddExtensions Method. After that you can call it like this: {MyVariable:ToJSON()}
Smart.Default.AddExtensions(new ToJSONFormatter());
public class ToJSONFormatter : IFormatter
{
public string Name { get; set; } = "ToJSON";
public bool CanAutoDetect { get; set; } = false;
private JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { DateFormatString = "yyyy-MM-ddTHH:mm:ss" };
//{Data:ToJSON()}
public bool TryEvaluateFormat(IFormattingInfo formattingInfo)
{
formattingInfo.Write(JsonConvert.SerializeObject(formattingInfo.CurrentValue));
return true;
}
}

Related

Parse JObject into a mixed object (static + dynamic fields)

given the following json
{
"$$href": "http://localhost:8080/url1",
"name": "Sebastian Slutzky"
}
I'd like to deserialize it into an object like this one
public class DomainObject
{
[JsonProperty("$$href")]
public string href { get; set; }
public JObject this[string key] => throw new NotImplementedException();
}
so that arbitrary properties (like name can be accessed dynamically)
var href = domainObject.href;
var name = domainObject["name"] as string;
My current implementation is by passing the JObject to the constructor of my object, and decorate it (i.e. composition). Is there a way of solving this by inheritance instead (i.e. by extending JObject?
Any other solution?
You could make use of JsonExtensionData. For example
public class DomainObject
{
[JsonProperty("$$href")]
public string href { get; set; }
[JsonExtensionData]
private IDictionary<string, JToken> UnknownTypes;
public JToken this[string key] => UnknownTypes[key];
}
The Indexer now allows you to retrieve the values of dynamic properties with key as the following.
var result = JsonConvert.DeserializeObject<DomainObject>(json);
var name = result["name"].Value<string>();

Data Annotations to sanitize request and response before logging

I'm looking for a reliable solution to log details of requests and responses made to and from our controllers. However, some of the data passing through contains sensitive information that should not be written to a log.
In the controller, the inbound request is bound to a single model from the request body, and as the request is answered, a single model is passed to the Ok() result like this (very simplified):
[HttpGet]
[Route("Some/Route")]
public IHttpActionResult SomeController([FromBody] RequestType requestObj)
{
ResponseType responseObj = GetResponse(requestObj)
return this.Ok(responseObj);
}
Now my goal is to somehow log the contents of the request and response object at the beginning and end of the controller, respectively. What I would like to do is bind the models first, then log out their attributes. An example of the RequestType is something like:
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
public string Password{ get; set; }
}
And the log would look something like:
[date-time] Request to SomeController:
SomeAttribute: "value_from_request"
AnotherAttribute: "another_value"
Password: "supersecret123"
Now clearly we don't want the password to be logged. So I would like to create a custom data annotation that would not log certain fields. Its use would look like this (updated RequestType):
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
[SensitiveData]
public string Password{ get; set; }
}
Where would I start with this? I'm not incredibly familliar with .NET, but know that there are many sort of magic classes that can be subclassed to override some of their functionality. Is there any such class that can help here? Even better, is there any way to do this during the model binding? So we could catch errors that occur during model binding as well?
We should be able to achieve what you're looking for with an ActionFilterAttribute.
Capture Requests Attribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class CaptureRequestsAttribute : ActionFilterAttribute // *IMPORTANT* This is in the System.Web.Http.Filters namespace, not System.Web.Mvc
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var messages = actionContext.ActionArguments.Select(arg => GetLogMessage(arg.Value));
var logMessage = $"[{DateTime.Now}] Request to " +
$"{actionContext.ControllerContext.Controller}]:\n{string.Join("\n", messages)}";
WriteToLog(logMessage);
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var result = actionExecutedContext.Response.Content as ObjectContent;
var message = GetLogMessage(result?.Value);
var logMessage = $"[{DateTime.Now}] Response from " +
$"{actionExecutedContext.ActionContext.ControllerContext.Controller}:\n{message}";
WriteToLog(logMessage);
base.OnActionExecuted(actionExecutedContext);
}
private static void WriteToLog(string message)
{
// todo: write you logging stuff here
}
private static string GetLogMessage(object objectToLog)
{
if (objectToLog == null)
{
return string.Empty;
}
var type = objectToLog.GetType();
var properties = type.GetProperties();
if (properties.Length == 0)
{
return $"{type}: {objectToLog}";
}
else
{
var nonSensitiveProperties = type
.GetProperties()
.Where(IsNotSensitiveData)
.Select(property => $"{property.Name}: {property.GetValue(objectToLog)}");
return string.Join("\n", nonSensitiveProperties);
}
}
private static bool IsNotSensitiveData(PropertyInfo property) =>
property.GetCustomAttributes<SensitiveDataAttribute>().Count() == 0;
}
Sensitive Data Attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class SensitiveDataAttribute : Attribute
{
}
Then, you can just add it to your WebApi controller (or a specific method in it):
[CaptureRequests]
public class ValuesController : ApiController
{
// .. methods
}
And finally your models can just add the SensitiveDataAttribute:
public class TestModel
{
public string Username { get; set; }
[SensitiveData]
public string Password { get; set; }
}
This does not make use of DataAnnotations,however, One way that comes to mind would be to use the serialization. If your payload is within a reasonable size you could serialize and deserialize your RequestType class when reading and writing to/from a log. This would require a custom serialization format or making use of the default, xml.
[Seriliazeble()]
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
[NonSerialized()]
public string Password{ get; set; }
}
Using the above attribute will omit Password from serialization. Then you copuld proceed to Logger.Log(MySerializer.Serialize(MyRequest)); and your sensitive data will be omitted.
This link describes the approach in detail.
For xml serialization, simply use the XmlSerializer class.
public class MySerializationService
{
public string SerializeObject(object item)
{
XmlSerializer serializer = new XmlSerializer(item.GetType());
System.IO.MemoryStream aMemStr = new System.IO.MemoryStream();
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(aMemStr, null);
serializer.Serialize(writer, item);
string strXml = System.Text.Encoding.UTF8.GetString(aMemStr.ToArray());
return strXml;
}
public object DeSerializeObject(Type objectType, string objectString)
{
object obj = null;
XmlSerializer xs = new XmlSerializer(objectType);
obj = xs.Deserialize(new StringReader(objectString));
return obj;
}
}
Then using the above or similar methods you can read and write in a custom format.
Write :
string logData=new MySerializationService().SerializeObject(myRequest);
Read :
RequestType loggedRequest= (RequestType)new MySerializationService().DeSerializeObject(new RequestType().GetType(), logData);

Handle querystring coontaining [] in asp.net

What is the best way to handle the queries[search] and sorts[Driver1] parameters in the following querystring in asp.net?
?queries[search]=greenock&id=20&sorts[Driver1]=1
I tried using this model but only id was bound:
public class ICRSRequestModel
{
public int ID { get; set; }
public ICollection<string> Sorts { get; set; }
public ICollection<string> Queries { get; set; }
}
I don't have the option of changing the requesting application unfortunately, and the string contained inside [] could be any unknown value.
If the property is
public ICollection<string> Queries { get; set; }
Then the query string would need to be
?queries[0]=greenock
you would need to change the property to
public Dictionary<string, string> Queries { get; set; }
so that the query string could be
?queries[search]=greenock
The key will be "search" and the value will be "greenock"
Note this will only work for a single queries value. ?queries[search]=greenock?queries[anotherKey]=anotherValue will not work
Sorry, not got 50 rep points yet else I would have commented with this probably useless comment, but here goes..
I'm sure there's a better way using MVC bindings but if all else fails it might be worth taking the QueryString from the Server.Request object and splitting the string up to extract the information you want. You can get them in to a keyvaluepair collection using the code I had lying around in a project, I'm sure it can be manipulated for your needs.
Dictionary<string, string> dictionary = new Dictionary<string, string>();
foreach (string part in queryString.Split(new char[] { '&' }))
{
if (!string.IsNullOrEmpty(part))
{
string[] strArray = part.Split(new char[] { '=' });
if (strArray.Length == 2)
{
dictionary[strArray[0]] = strArray[1];
}
else
{
dictionary[part] = null;
}
}
}

serializing only parts of an object with json

I have an object called MyObject that has several properties. MyList is a list of MyObject that I populate with a linq query and then I serialize MyList into json. I end up with something like this
List<MyObject> MyList = new List<MyObject>();
MyList = TheLinqQuery(TheParam);
var TheJson = new System.Web.Script.Serialization.JavaScriptSerializer();
string MyJson = TheJson.Serialize(MyList);
What I want to do is serialize only parts of MyObject. For instance, I might have Property1, Property2...Propertyn and I want MyJson to only include Property3, Property5 and Property8.
I thought of a way to do this by creating a new object with only the properties I want and from there create a new list for the serialization. Is this the best way or is there a better/faster way?
Thanks.
// simple dummy object just showing what "MyObject" could potentially be
public class MyObject
{
public String Property1;
public String Property2;
public String Property3;
public String Property4;
public String Property5;
public String Property6;
}
// custom converter that tells the serializer what to do when it sees one of
// the "MyObject" types. Use our custom method instead of reflection and just
// dumping properties.
public class MyObjectConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new ApplicationException("Serializable only");
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
// create a variable we can push the serailized results to
Dictionary<string, object> result = new Dictionary<string, object>();
// grab the instance of the object
MyObject myobj = obj as MyObject;
if (myobj != null)
{
// only serailize the properties we want
result.Add("Property1", myobj.Property1);
result.Add("Property3", myobj.Property3);
result.Add("Property5", myobj.Property5);
}
// return those results
return result;
}
public override IEnumerable<Type> SupportedTypes
{
// let the serializer know we can accept your "MyObject" type.
get { return new Type[] { typeof(MyObject) }; }
}
}
And then where ever you're serializing:
// create an instance of the serializer
JavaScriptSerializer serializer = new JavaScriptSerializer();
// register our new converter so the serializer knows how to handle our custom object
serializer.RegisterConverters(new JavaScriptConverter[] { new MyObjectConverter() });
// and get the results
String result = serializer.Serialize(MyObjectInstance);

How do i get Intellisense for <T> class?

i'm creating an html.helper for a 3rd party javascript grid component. i'm passing my gridextension my viewmodel.
in my viewmodel class i've got custom attributes on my properties describing how each column is displayed.
in my gridextension, i want to then serialize my class of T. in my CreateSerializedRow method i'd like to be able to do something like row. <- and get intellisense for my class. but how to i get intellisense for the members of class T without an explicit cast?
public class GridData<T>
{
#region Fields
private List<Dictionary<string, object[]>> _attributes;
private static IList<T> _dataSource;
#endregion
#region Properties
public string Align { get; set; }
public string Header { get; set; }
public string JsonData { get; set; }
public string Sorting { get; set; }
public string Width { get; set; }
#endregion
#region Public Methods
public void Serialize(IList<T> dataSource, List<Dictionary<string, object[]>> attributes)
{
_dataSource = dataSource;
_attributes = attributes;
JsonData = _dataSource.Count == 0 ? string.Empty : BuildJson();
}
#endregion
#region Private Methods
private static string BuildJson()
{
var sbJson = new StringBuilder();
var listCount = _dataSource.Count;
sbJson.Append("{page: 1, total:" + listCount + ", rows: [");
for (var i = 0; i < listCount; i++)
{
var serialized = CreateSerializedRow(i);
sbJson.Append(serialized);
if (i < listCount - 1)
sbJson.Append(",");
}
sbJson.Append("]}");
return sbJson.ToString();
}
private static string CreateSerializedRow(int index)
{
var row = _dataSource[index];
var sb = new StringBuilder();
//sb.Append("{id:'" + Id + "',data:[");
//sb.Append(String.Format("'{0}',", GroupName.RemoveSpecialChars()));
//sb.Append(String.Format("'{0}',", Description));
//sb.Append(String.Format("'{0}',", CreatedBy));
//sb.Append(String.Format("'{0}',", CreatedDate.ToShortDateString()));
//sb.Append(String.Format("'{0}',", EmailSubject.RemoveSpecialChars()));
//sb.Append(String.Format("'{0}',", EmailBody));
//sb.Append(String.Format("'{0}',", UpdatedBy));
//sb.Append(String.Format("'{0}'", UpdatedDate.ToShortDateString()));
//sb.Append("]}");
return sb.ToString();
}
#endregion
}
The best you can do is use Generic constraints, which specify that T must be castable to a specific type. See http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx#csharp_generics_topic4 for more information.
The syntax is more or less the following:
public class MyClass<T> where T : ISomethingOrOther
{
}
At least this way, you can limit T to an interface type and code against that abstraction with Intellisense support.
With what you're trying to do you'd probably have to use reflection to cycle through the properties and output the values. You might be better off making GridData an abstract class and override a method which outputs the row of data for each data class.
Or create a generic interface which has a Serialize() method that outputs a string of the objects values in the expected format. Have each model class implement this interface and then have the GridData class constrained to this interface. Assuming these are ViewModel classes, it should be a reasonable design.
If T is always a known interface or class you can do:
public class GridData<T>
where T:MyClass
{
...
}

Resources