Serializing/Deserializing Command Object - c#

I'm attempting to serialize (and later deserialize) a command object to a string (preferably using the JavaScriptSerializer). My code compiles, however when I serialize my command object it returns an empty Json string, i.e. "{}". The code is shown below.
The aim is to serialize the command object, place it in a queue, then deserialize it later so it can be executed. If the solution can be achieved with .NET 4 then all the better.
ICommand
public interface ICommand
{
void Execute();
}
Command Example
public class DispatchForumPostCommand : ICommand
{
private readonly ForumPostEntity _forumPostEntity;
public DispatchForumPostCommand(ForumPostEntity forumPostEntity)
{
_forumPostEntity = forumPostEntity;
}
public void Execute()
{
_forumPostEntity.Dispatch();
}
}
Entity
public class ForumPostEntity : TableEntity
{
public string FromEmailAddress { get; set; }
public string Message { get; set; }
public ForumPostEntity()
{
PartitionKey = System.Guid.NewGuid().ToString();
RowKey = PartitionKey;
}
public void Dispatch()
{
}
}
Empty String Example
public void Insert(ICommand command)
{
// ISSUE: This serialization returns an empty string "{}".
var commandAsString = command.Serialize();
}
Serialization Extension Method
public static string Serialize(this object obj)
{
return new JavaScriptSerializer().Serialize(obj);
}
Any help would be appreciated.

Your DispatchForumPostCommand class has no properties to serialize. Add a public property to serialize it. Like this:
public class DispatchForumPostCommand : ICommand {
private readonly ForumPostEntity _forumPostEntity;
public ForumPostEntity ForumPostEntity { get { return _forumPostEntity; } }
public DispatchForumPostCommand(ForumPostEntity forumPostEntity) {
_forumPostEntity = forumPostEntity;
}
public void Execute() {
_forumPostEntity.Dispatch();
}
}
I now get the following as the serialized object (I removed the inheritance of TableEntity for testing purposes):
{"ForumPostEntity":{"FromEmailAddress":null,"Message":null}}
If you want to deserialize the object as well, then you will need to add the public setter for the property, else the deserializer will not be able to set it.

Related

Add property to all responses in asp.net core

I have an API with multiple endpoints. I'd like to add a property to all endpoint responses, without adding it to each endpoint response model individually.
Ex:
public class MyClass
{
public string MyProperty { get; set; } = "Hello";
}
public class MyOtherClass
{
public string MyOtherProperty { get; set; } = "World";
}
public class MyController : ControllerBase
{
[HttpPost]
public async Task<ActionResult<MyClass>> EndpointOne(POSTData data)
{
// implementation omitted
}
[HttpPost]
public async Task<ActionResult<MyOtherClass>> EndpointTwo(POSTOtherData otherData)
{
// implementation omitted
}
}
Calling either endpoint returns a JSON representation of MyClass or MyOtherClass as appropriate - i.e.
{ "MyProperty":"Hello" } or { "MyOtherProperty":"World" }
I want to add a property, say a string ApiName, to all endpoints in the API, so that the result of the above code would be either (as appropriate)
{ "MyProperty":"Hello", "ApiName":"My awesome API" }
or
{ "MyOtherProperty":"World", "ApiName":"My awesome API" }
Is there a way to hook into the JSON-stringified result just before returning and add a top-level property like that? If so, I presume I'd have to wire it up in startup.cs, so I've been looking at app.UseEndpoints(...) methods, but haven't found anything that's worked so far. Either it's not added the property, or it's replaced the original result with the new property.
Thanks in advance!
Use Newtonsoft.Json in your net web api
Register a custom contract resolver in Startup.cs:
builder.Services.AddControllers()
.AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = CustomContractResolver.Instance);
The implementation:
public class CustomContractResolver : DefaultContractResolver {
public static CustomContractResolver Instance { get; } = new CustomContractResolver();
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
// add new property
...
properties.Add(newProp);
return properties;
}}
See more Json.net Add property to every class containing of a certain type
You can add a base class with the shared property. Should work for both XML and JSON.
public class MyApiClass
{
public string ApiName => "MyAwesomeApi";
}
public class MyClass : MyApiClass
{
public string MyProperty { get; set; } = "Hello";
}
public class MyOtherClass : MyApiClass
{
public string MyOtherProperty { get; set; } = "World";
}
public class MyController : ControllerBase
{
[HttpPost]
public async Task<ActionResult<MyClass>> EndpointOne(POSTData data)
{
// implementation omitted
}
[HttpPost]
public async Task<ActionResult<MyOtherClass>> EndpointTwo(POSTOtherData otherData)
{
// implementation omitted
}
}
My 0.02 cents says to implement an abstract base class.
Abstract class inheritance look similar to a standard inheritance.
public class MyClass:MyAbstractClass
{
[JsonPropertyName("Class Property")]
public string MyProperty { get; set; } = "Hello";
}
public class MyOtherClass:MyAbstractClass
{
[JsonPropertyName("Class Property")]
public string MyOtherProperty { get; set; } = "World";
}
However the abstract class will allow you to implement additional features in the event you need them in the future.
public abstract class MyAbstractClass{
[JsonPropertyName("API Name")]
public string ApiName{get;set;}="My Aweomse API";
//Just a thought if you want to keep track of the end point names
//while keeping your object names the same
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string EndPointName{
get{
return get_endpoint_name();
}}
private string get_endpoint_name(){
return this.GetType().Name;
}
//May as well make it easy to grab the JSON
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string As_JSON{
get {
return to_json();
}}
private string to_json(){
object _myObject = this;
string _out;
JsonSerializerOptions options =
new JsonSerializerOptions {
WriteIndented = true };
_out =
JsonSerializer.Serialize(_myObject, options);
return _out;
}
}
Probably should have implemented a generic return object, then you could just loop through the task results. I suppose you still can if you have the task return only the JSON string.
public static void run(){
Task<MyClass> _t0 = task0();
Task<MyOtherClass> _t1 = task1();
Task[] _tasks = new Task[]{_t0,_t1};
Task.WhenAll(_tasks).Wait();
Console.WriteLine(""
+$"{_t1.Result.ApiName}:\n"
+$"End Point: {_t1.Result.EndPointName}:\n"
+$"JSON:\n{_t1.Result.As_JSON}");
Console.WriteLine(""
+$"{_t0.Result.ApiName}:\n"
+$"End Point: {_t0.Result.EndPointName}:\n"
+$"JSON:\n{_t0.Result.As_JSON}");
}
private static Task<MyClass> task0(){
return Task.Run(()=>{
Console.WriteLine("Task 0 Doing Something");
return new MyClass();
});
}
private static Task<MyOtherClass> task1(){
return Task.Run(()=>{
Console.WriteLine("Task 1 Doing Something");
return new MyOtherClass();
});
}
And of course the aweosome...awesome:-) results:
Another thought is that you could implement your two different tasks as abstract methods, but that's a different conversation all together.
In addition to all of the great answers, I prefer to use Action Filter and ExpandoObject.
In Program File you should add your custom action Filter.
builder.Services.AddControllers(opt =>
{
opt.Filters.Add<ResponseHandler>();
});
and ResponseHandler acts like below:
public class ResponseHandler : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var propertyInfo in (context.Result as ObjectResult).Value.GetType().GetProperties())
{
var currentValue = propertyInfo.GetValue((context.Result as ObjectResult).Value);
expando.Add(propertyInfo.Name, currentValue);
}
dynamic result = expando as ExpandoObject;
result.ApiName = context.ActionDescriptor.RouteValues["action"].ToString();
context.Result = new ObjectResult(result);
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
}

Placing different generic types into a data structure, and then handling them upon removal

I posted this question yesterday but it was marked as a duplicate of C# - Multiple generic types in one list
To clarify, the answer in that problem shows how to correctly place multiple generic types into a single list. However that's not my problem. My problem is that, upon removing items from the list, I need to know what type they are in order to handle them correctly.
As a starting point, I am using the answer to the above question because it does have a good solution for placing items of multiple types into a data structure. As you can see below, I have created an abstract base ScheduleItem class, and then an inheriting generic ScheduleItem class. That allows me pass to in different types of generic to the same priority queue.
However when I dequeue these items, they are treated as the base class, which do not have the properties of the inheriting class that I am trying to access. Therefore trying to get any data out of them doesn't work. Even though, in the debugger, I can clearly see that the object I'm pulling out contains the data I want, I get errors trying to access it. I assume this is because when I'm dequeuing an object I don't know what generic type was associated with it, and so I get the base class, which has no properties associated.
public class ScheduleManager
{
PriorityQueue<ScheduleItem> schedule = new PriorityQueue<ScheduleItem>();
//case: adding an item with int data
public void AddScheduleItem(int steps, string eventName, int param) {
schedule.Enqueue(new ScheduleItem<int>(eventName, param, steps), steps);
}
//case: adding an item with bool data
public void AddScheduleItem(int steps, string eventName, bool param)
schedule.Enqueue(new ScheduleItem<bool>(eventName, param, steps), steps);
}
public ScheduleManager()
{
schedule.Enqueue(new ScheduleItem<bool>("test", true, 1), 1);
ScheduleItem test = schedule.Dequeue();
Debug.Log(test.ScheduledStep); //Coming up null
Debug.Log(test.Data); //Coming up null
test.Activate(); //Causing error
}
//The abstract base class
abstract class ScheduleItem { }
//The inheriting generic class. This is the one that actually
//holds data I need
class ScheduleItem<T> : ScheduleItem where T : struct {
public T Data { get; private set; }
public string EventName { get; private set; }
public int ScheduledStep { get; private set; }
public ScheduleItem(string eventName, T data, int scheduledStep) {
EventName = eventName;
Data = data;
ScheduledStep = scheduledStep;
}
public void Activate() {
if(typeof(T) == typeof(int)) {
int data = (int)Convert.ChangeType(Data, typeof(int));
EventManager.TriggerIntEvent(EventName, data);
}
if (typeof(T) == typeof(bool))
{
bool data = (bool)Convert.ChangeType(Data, typeof(bool));
EventManager.TriggerBoolEvent(EventName, data);
}
}
}
}
Any help would be greatly appreciated!
Back to OOP basics.
You want EventName and ScheduledStep to be available regardless of the type of ScheduleItem. Therefore they need to be on the ScheduleItem class itself.
You also want the behaviour of each ScheduleItem subclass to be different, depending on the type of its data. An easy way to do this is to have a different subclass per type of data, which has a different Activate method.
public abstract class ScheduleItem
{
public string EventName { get; }
public int ScheduledStep { get; }
protected ScheculeItem(string eventName, int scheduledStep)
{
EventName = eventName;
ScheduledStep = scheduledStep;
}
public abstract void Activate();
}
public class IntScheduleItem
{
private readonly int data;
public IntScheduleItem(string eventName, int scheduledStep, int data)
: base(eventName, int scheduledStep)
{
this.data = data;
}
public override void Activate()
{
EventManager.TriggerIntEvent(EventName, data);
}
}
... and so on
If the only difference between the different types of ScheduleItem is the EventManager method which is called, you could do something like this instead of having separate IntScheduleEvent, BoolScheduleEvent, etc, classes:
public class ScheduleItem<T> : ScheduleItem
{
private readonly T data;
private readonly Action<string, T> activator;
public ScheduleItem(string eventName, int scheduledStep, int data, Action<string, T> activator)
: base(eventName, int scheduledStep)
{
this.data = data;
this.activator = activator;
}
public override void Activate()
{
activator(EventName, data);
}
}
...
public void AddScheduleItem(int steps, string eventName, int param) {
schedule.Enqueue(new ScheduleItem<int>(eventName, steps, param, EventManager.TriggerIntEvent), steps);
}
You could even take it one step further and do away with the class hierarchy at all:
public class ScheduleItem
{
public string EventName { get; }
public int ScheduledStep { get; }
private readonly Action activator;
protected ScheculeItem(string eventName, int scheduledStep, Action activator)
{
EventName = eventName;
ScheduledStep = scheduledStep;
this.activator = activator;
}
public void Activate() => activator();
}
...
public void AddScheduleItem(int steps, string eventName, int param) {
schedule.Enqueue(new ScheduleItem(eventName, steps, () => EventManager.TriggerIntEvent(eventName, param)), steps);

Custom attributes not behaving like data annotations

I am trying to create a custom attribute in console application but it is not working. My custom attribute never gets called. I found a good example here Custom Attribute not being hit
but not happy with its implementation.
I am wondering how data annotations works in MVC. we don't have to call it separately.
Is MVC calling those data annotations attribute behind the scene?
I wish to create custom attribute that I can use it on any class property same like data annotations attribute. But calling it separately like in above link is not what i am looking.
Here is what I have tried:
using System;
namespace AttributePractice
{
[AttributeUsage(AttributeTargets.Property)]
public class CustomMessageAttribute : Attribute
{
public static readonly CustomMessageAttribute Default = new CustomMessageAttribute();
protected string Message { get; set; }
public CustomMessageAttribute() : this(string.Empty)
{
Console.WriteLine("Default message is empty");
}
public CustomMessageAttribute(string message)
{
Message = message;
}
public string MyMessage =>
Message;
public override bool Equals(object obj)
{
if (obj == this)
return true;
if (obj is CustomMessageAttribute customMessageAttribute)
return customMessageAttribute.Message == MyMessage;
return false;
}
public override int GetHashCode()
{
return MyMessage.GetHashCode();
}
public override bool IsDefaultAttribute()
{
return Equals(Default);
}
}
public class Person
{
//This never works
// I am looking to use this attribute anywhere without calling it
// separately , same like data annotations
[CustomMessage("Hello world")]
public string Name { get; set; }
public int Age { get; set; }
public void DisplayPerson()
{
Console.WriteLine(Name);
Console.WriteLine(Age);
}
}
internal static class Program
{
private static void Main(string[] args)
{
var personObj = new Person
{
Name = "Tom",
Age = 28
};
personObj.DisplayPerson();
}
}
}
Can anybody tell me how to make my custom attribute works like data annotation way?
yes, if you need 10 custom attributes, you should create 10 separate.

Storing a function that may have parameter or not, to variable. Action<T> with unknown numbers and types of variables

I'm working on a command parser class for console application but I got stucked at the storing command function to variable. I want to store a function that may have parameter or not, to commandFunc variable in Command object.
These codes work with functions without parameters. How can I get parameter support to this? For example: a function like output(string msg){ .. }
class Program
{
static void Main(string[] args)
{
CommandParser.AddCommand(new Command() { commandText = "time", commandFunc = new Action(time) });
CommandParser.Loop();
}
private static void time()
{
Console.WriteLine(DateTime.Now.ToLongTimeString());
}
}
In CommandParser.Loop, it searches for inputted command in List< Command > and then runs Execute method from it.
public class Command
{
public string commandText { get; set; }
public Action commandFunc { get; set; }
public void Execute()
{
this.commandFunc();
}
}
For example the execute method can be someting like this:
public void Execute(Parameters params)
{
this.commandFunc(params);
}
PS: CommandParser.Loop()
public static void Loop()
{
while(true)
{
Console.Write(prefix);
string[] input = Console.ReadLine().Split(' ');
Command cmdInput = commands.Find(x => x.commandText.Contains(input[0]));
if(cmdInput != new Command())
{
cmdInput.Execute();
}
else
{
Console.WriteLine(prefix + "Command not found!");
}
}
}
Well what you basically need to do is extend the object hierarchy.
In C#, generics don't allow Something<void>, so what you need to do is:
public interface ICommand
{
void Execute();
}
This is your current implementation with the interface added
public class Command : ICommand
{
public string commandText { get; set; }
public Action commandFunc { get; set; }
public void Execute()
{
this.commandFunc();
}
}
And is a generic implementation for delegate with arguments
public class Command<T> : ICommand
{
public string commandText { get; set; }
public Action<T> commandFunc { get; set; }
public T commandParam { get; set; }
public void Execute()
{
this.commandFunc(commandParam);
}
}
If you need implementation for more parameters, you could either copy the original one or use Tuple class as the generic parameter (e.g. Tuple<string, int>).
As mentioned by Jon Skeet in comments:
Another thing is that you'll probably need to parse the parameter(s) (represented by commandParam) inside these generic commands. You should initialize these commands with a parameter (e.g. delegate) to parse the parameter(s). Doing this outside of the commands would be a mess and break the whole genericity/interface idea. But it might work on a smaller scale.

Deserialize json into C# object for class which has default private constructor

I need to deserialize json for following class.
public class Test
{
public string Property { get; set; }
private Test()
{
//NOTHING TO INITIALIZE
}
public Test(string prop)
{
Property = prop;
}
}
I can create an instance of Test like
var instance = new Test("Instance");
considering my json something like
"{ "Property":"Instance" }"
How shall I create an object of Test class as my default constructor is private and I am getting object where Property is NULL
I am using Newtonsoft Json parser.
You can make Json.Net call the private constructor by marking it with a [JsonConstructor] attribute:
[JsonConstructor]
private Test()
{
//NOTHING TO INITIALIZE
}
Note that the serializer will still use the public setters to populate the object after calling the constructor.
Another possible option is to use the ConstructorHandling setting:
JsonSerializerSettings settings = new JsonSerializerSettings
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
};
Test t = JsonConvert.DeserializeObject<Test>(json, settings);
It doesn't seem like you need to take any extra steps.
Using Json.NET v6.0.8, the following C# program works inside LINQPad:
void Main()
{
var o = JsonConvert.DeserializeObject<Test>("{\"Property\":\"Instance\"}");
Debug.Assert(o.Property == "Instance",
"Property value not set when deserializing.");
}
public class Test
{
public string Property { get; set; }
private Test()
{
}
public Test(string propertyValue)
{
Property = propertyValue;
}
}
No need to create a Serializer setting and give assign ConstructorHandling here. Please remember to define the [JsonConstructor] attribute to the private constructor.
I have similar case with abstract BaseNode.cs and its concrete ComputerNode.cs implementation. You can create the classes, copy/paste the code below and do some experiment.
public abstract class BaseNode
{
[JsonConstructor] // ctor used when Json Deserializing
protected BaseNode(string Owner, string Name, string Identifier)
{
this.Name = Name;
this.Identifier = Identifier;
}
// ctor called by concrete class.
protected BaseNode(string [] specifications)
{
if (specifications == null)
{
throw new ArgumentNullException();
}
if (specifications.Length == 0)
{
throw new ArgumentException();
}
Name = specifications[0];
Identifier = specifications[1];
}
public string Name{ get; protected set; }
public string Identifier { get; protected set; }
}
public class ComputerNode: BaseNode
{
public string Owner { get; private set; }
[JsonConstructor] // not visible while creating object from outside and only used during Json Deserialization.
private ComputerNode(string Owner, string Name, string Identifier):base(Owner, Name, Identifier)
{
this.Owner = Owner;
}
public ComputerNode(string[] specifications):base(specifications)
{
Owner = specifications[2];
}
}
For JSon Read and Write following code helps -
public class Operation<T>
{
public string path;
public Operation()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "nodes.txt");
if (File.Exists(path) == false)
{
using (File.Create(path))
{
}
}
this.path = path;
}
public void Write(string path, List<T> nodes)
{
var ser = JsonConvert.SerializeObject(nodes, Formatting.Indented);
File.WriteAllText(path, ser);
}
public List<T> Read(string path)
{
var text = File.ReadAllText(path);
var res = JsonConvert.DeserializeObject<List<T>>(text);
return res;
}
}
All the best!
Today the short answer is: Rename the constructor parameter prop to property and your code will work fine.
public class Test
{
public string Property { get; }
public Test(string property)
{
Property = property;
}
}
Console.WriteLine(
JsonConvert.DeserializeObject(new Test("Instance")));
Newtonsoft.Json supports initializing properties using constructor parameters out of the box, without needing to set any additional attributes or changing any settings. The only constraint is that the parameter name needs to be a case insensitive match to the property name.
I discovered today that having a public constructor that takes parameters and no declared unparameterized constructor causes NewtonSoft to attempt to call the public constructor, the only one that it can find, since there is no explicit default constructor, and it cannot apparently find and call the default constructor provided by the framework unless it is the only constructor.
Explicitly declaring a default constructor causes NewtonSoft to call the correct (unparameterized) constructor.

Categories

Resources