EDIT I updated my question for completeness.
I have incoming REST calls from an iPHone client. It is meant to consume type-specific objects
in response to generic requests. For example:
http://localhost:81/dashboard/group/id/0
returns data from the Regions type
http://localhost:81/dashboard/group/id/1
returns data from the Customers type
http://localhost:81/dashboard/group/id/2
returns data from the Users type
and so on.
The WCF Dashboard.svc service exposes a base method GetGroupById
which I use to determine and return the type-specific response:
public class Dashboard : GroupBase, Contracts.IDashboardService
{
private string name = String.Empty;
public Dashboard() : base()
{
if (!ServiceSecurityContext.Current.PrimaryIdentity.IsAuthenticated)
throw new WebException("Unauthorized: Class: Dashboard, Method: Dashboard()",
System.Net.HttpStatusCode.Forbidden);
name = ServiceSecurityContext.Current.PrimaryIdentity.Name;
}
public override System.IO.Stream GetGroupById(string id)
{
return base.GetGroupById(id);
}
}
Now, inside my abstract base class the GetGroupById has a switch/case statement that populates
and returns unique data transfer objects based on the corresponding groupid parameter:
public abstract class GroupBase
{
protected GroupBase () { }
public virtual Stream GetGroupById(string id)
{
// I have tried assigning response to null or, in this case,
// assigning it to a random service object. I have also tried
// IObjectFactory response; The last fails at compile-time and
// the other two always produce null
IObjectFactory response =
ObjectFactory<IObjectFactory, UserService>.Create();
var groupId = System.Convert.ToInt32(id);
var serializer = new JavaScriptSerializer();
byte[] bytes = null;
var message = String.Empty;
try
{
switch (groupId)
{
case 0: // regions
response = ObjectFactory<IObjectFactory, RegionService>.Create();
break;
case 1: // customers
response = ObjectFactory<IObjectFactory, CustomerService>.Create();
break;
case 2: // users
response = ObjectFactory<IObjectFactory, UserService>.Create();
break;
}
}
catch (EngageException oops)
{
message = oops.Message;
}
bytes = Encoding.UTF8.GetBytes(serializer.Serialize(response));
return new MemoryStream(bytes);
}
}
A customer ObjectFactory class is used to create the type-specific object:
public static class ObjectFactory where T : F, new()
{
public static F Create()
{
return new T();
}
}
WHERE I AM HAVING PROBLEMS IS what is going on under the hood of my ObjectFactory. I am always
getting ** null ** back. For example, consider the following REST HTTP GET:
http://localhost:81/dashboard/group/id/2
The above command is asking for a JSON string of all Users in the database. Accordingly, the
UserService class is passed into the ObjectFactory method.
public class UserService : IObjectFactory
{
DomainObjectsDto IObjectFactory.Children
{
get
{
return new Contracts.DomainObjectsDto(UserRepository
.GetAllUsers().Select
(p => new Contracts.DomainObjectDto
{
Title = GroupTypes.Customer.ToString(),
Id = p.CustomerId.ToString(),
Type = p.GetType().ToString()
}));
}
}
string IObjectFactory.Method
{
get;
set;
}
string IObjectFactory.Status
{
get;
set;
}
etc...
And, the readonly Get property gets data from the UserRepository, populates the Data Transfer Object
(illustrated below)
[DataContract]
public class DomainObjectDto
{
[DataMember]
public string Title { get; set; }
[DataMember]
public string Id { get; set; }
[DataMember]
public string Type { get; set; }
}
[CollectionDataContract]
public class DomainObjectsDto : List<DomainObjectDto>
{
public DomainObjectsDto() { }
public DomainObjectsDto(IEnumerable<DomainObjectDto> source) : base(source) { }
}
And should return the serialized JSON string of User data to the client. But, my generic type T in my object factory class is always null:
public static F Create()
{
return new T(); // <-- always null!
}
Any ideas??
Hard to tell without seeing the invocation of your factory in context, but my gut feel is that groupId is not in the switch range and thus you are getting the null you defaulted it to. I would add a default case and throw an out of range exception and see if that's your problem.
It's a good idea to add default cases to your switch statements, like:
default:
throw new Exception( "groupId " + groupId + " not found" );
Change the line IObjectFactory response = null; to remove the default, i.e. IObjectFactory response;. Now the compiler will tell you if there is a branch that doesn't assign it (of course, it can't tell you if you assign to null somehow). Note also that there are at least 2 ways of getting null from a new (etc), but these are edge cases - I doubt they are contributing (mentioned for completeness only).
Related
I am working on a websocket client application. The server send messages in JSON format and I want to deserialize it. There have one string in the JSON format data that shows the type of message (it has about 50 types today, maybe it will have more in the future).
So I have written a large switch statement like this:
switch(type){
case "type1":
DoSth<T1>(DeserializeFunction<T1>(message));
break;
case "type2":
DoSth<T2>(DeserializeFunction<T2>(message));
break;
//...
}
Is it possible to optimize this statement?
This is the model:
public record EventMessage<T> where T : IEventExtraBody
{
// this will always be 0
[JsonPropertyName("s")]
public int EventType { get; set; }
[JsonPropertyName("sn")]
public long SerialNumber { get; set; }
[JsonPropertyName("d")]
public EventMessageData<T> Data { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this);
}
}
public record EventMessageData<T> where T : IEventExtraBody
{
// Some other properties
[JsonPropertyName("extra")]
public EventMessageExtra<T> Extra { get; set; }
}
public record EventMessageExtra<T> where T : IEventExtraBody
{
[JsonPropertyName("type")]
public string Type { get; set; } // this string indicates the type of message
[JsonPropertyName("body")]
public T Body { get; set; }
}
Body (an example):
public record ExitedGuildEvent : IEventExtraBody
{
[JsonPropertyName("user_id")]
public string UserId { get; set; }
[JsonPropertyName("exited_at")]
public long ExitedAt { get; set; }
}
When message arrived, I use JsonDocument to get the type string.
var typeString = JsonDocument.Parse(message.Text).RootElement.GetProperty("d").GetProperty("extra").GetProperty("type").GetString()
Then, I want to deserialize the message and publish it to MessageHub.
Deserializing the json string and publish:
_messageHub.Publish(JsonSerializer.Deserialize<EventMessage<BodyType>>(message.Text));
And because there are lots of BodyType, and EventMessage<Type.GetType("TypeClassPath")>(message.Text) is illegal, I write a large switch statement.
Maybe I have build a very bad model for this situation. I hope you can give me some advice.
You could replace switch-case with a hashmap. To do that you just need to move every case into separate function. Here you can create a factory method to help you to fill out a hashmap because cases are pretty similar
public class YourHub
{
private IMessageHub _messageHub = new MessageHub();
private Dictionary<string, Action<string, IMessageHub>> _methods;
public YourHub()
{
//fill out the hashmap for all types that you have
//make sure this hashmap is shared between operations
_methods = new Dictionary<string, Action<string, IMessageHub>>()
{
{"key1", CreateAction<EventMessage<ExitedGuildEvent>>() }
};
}
//factory method for the actions
private Action<string, IMessageHub> CreateAction<T>()
{
return (json, hub) => hub.Publish(JsonSerializer.Deserialize<T>(json, null));
}
public void ProcessMessage(string json)
{
var typeString = JsonDocument
.Parse(json)
.RootElement.GetProperty("d")
.GetProperty("extra")
.GetProperty("type")
.GetString();
if (!_methods.ContainsKey(typeString)) throw new NotSupportedException();
var method = _methods[typeString];
method(json, _messageHub);
}
}
This aproach won't give you a huge perfomance boost on 50 elements, but it looks cleaner. The runtime complexity is O(1) compared to O(n) with switch-case, but it takes O(n) additional space.
A better solution than a big switch would probably be to refactor DeserializeFunction into an interface and class.
Register It by type and then resolve it. Either with a DI container or by a dictionary where you map.
interface IMessageDeserializer {
object Deserialize(Message message);
}
class Type1Deserializer : IMessageDeserializer {
public object Deserialize(Message message){
// Implementation that returns a Type1
return new Type1(){
};
}
}
// Register your serializers (you can use also a DI container but this is simpler just to show how) in a dictionary, preferably reused
Dictionary<Type, IMessageDeserializer> serializers = new Dictionary<Type, IMessageDeserializer>();
serializers.Add("type1", new Type1Deserializer());
serializers.Add("type2", new Type2Deserializer());
serializers.Add("type3", new Type3Deserializer());
// When you need it, use it like this:
string type = "type1"; // This is from your other code
var message = GetMessage(); // This is from your other code
IMessageDeserializer serializer = serializers[type];
object deserializedMessage = serializer.Deserialize(message);
// To create your event message, either add a constraint to the T of IMessageDeserializer so you can pass it into another function that creates the event message or just simply return the messagehub message as json directly from your IMessageDeserializer implementation)
(I wrote this from memory so I apologise for any mistakes)
I'm writing a generic method to put set values on the base class
public class StageOne: DefaultValues
{
//StageOne properties
}
public class DefaultValues
{
public string status { get; set; }
public string message { get; set; }
}
private T SetValue<T>() where T : DefaultValues
{
T.message = "Good Job";
T.status = "Done";
return default(T);
}
I get an error on T.message and T.status; T is type parameter, which is not valid in the given context
I have already Googled it and I can't find my answer - please help.
Thanks.
If you want to set properties of the generic type, then you need an instance of the type. To get an instance we either need to have the caller pass one in as an argument, or create a new one (and if we choose this option, we need to include the new() constraint as well):
First option - have the caller pass in an instance of the type (no need for a return value in this case since the caller already has a reference to the instance we're changing):
private void SetValue<T>(T input) where T : DefaultValues
{
input.message = "Good Job";
input.status = "Done";
}
Second option - create a new instance of the type inside the method (note the added generic constraint, new()):
private T SetValue<T>() where T : DefaultValues, new()
{
T result = new T();
result.message = "Good Job";
result.status = "Done";
return result;
}
Which could be simplified to:
private static T SetValue<T>() where T : DefaultValues, new()
{
return new T {message = "Good Job", status = "Done"};
}
I'm trying to use a generic class to pass in a data object then uses the values within to complete CRUD operations.
class OrderState<TGrainState> : Grain, IState where TGrainState : class
{
protected TGrainState State { get; set; }
public Task Get()
{
using (var context = new SDbContext())
{
//Passing Null instance because not sure how to access the instance of the state object
var test = typeof(TGrainState).GetProperty("id").GetValue(null);
//int t = (int)test;
//var obj = context.orders.Where(x => x.Id == t);
//return Task.FromResult(obj);
}
return Task.CompletedTask;
}
}
TGrainState is the generic object I want to pass in.
public class State
{
public int Id { get; set; }
public DateTime Created { get; set; }
public string AssignedOrganization { get; set; }
public bool isComplete { get; set; }
public string assignedUser { get; set; }
}
This is the state class I'm attempting to pass into the generic class.
class OrderGrain : OrderState<State>, IOrder
{
public override Task OnActivateAsync()
{
//Should fill the State Object from the Db
Get();
//Sets the information contained in the State to the Object
this.orderInfo = new OrderInfo
{
Id = State.Id,
Created = State.Created,
AssignedOrganization = State.AssignedOrganization,
isComplete = State.isComplete,
assignedUser = State.assignedUser
};
return base.OnActivateAsync();
}
}
Class that inherits from the State Generic class that contains all of the CRUD operations.
So what I'm more or less trying to accomplish is how Microsoft Orleans has it's state setup where you create a state object, operate on that, then call Write(), Update(), Delete(), or Get() to perform the CRUD operation on the DB with Entity Framework using the state data declared.
The question is when I try to access the Values of the properties of the State object (State) inside the generic class (OrderState) I get the Error
System.Reflection.TargetException: 'Non-static method requires a
target.'
Link to the Orleans information that i'm trying to mimic.
Microsoft Orleans Grain Persistence
I might thinking about this wrong or just be completely wrong, so any help would be greatly appreciated.
I'm going to assume that this is a simple case of case-mismatching (pun not intended).
In this line:
var test = typeof(TGrainState).GetProperty("id").GetValue(null);
You are looking for the property id. However, your class declares it this way:
public int Id { get; set; }
The return value of the GetProperty method is "An object representing the public property with the specified name, if found; otherwise, null." Invoking GetValue on a null instance would result in the exception you're seeing.
I am trying to use generics on a List property for a class.
Basically I am using a message based service that would receive a collection of Message Requests. For each Message Request received, I would return a corresponding Message Response.
So my implementation would look something like this:
public class MessageRequest
{
private string _messageId;
private string _serviceMethod;
public MessageRequest(string id, string operation)
{
_messageId = MessageId;
_serviceMethod = operation;
}
public string MessageId { get { return _messageId; } }
public string ServiceMethod { get { return _serviceMethod; } }
}
public class MessageResponse
{
private List<T> _data; <--This does't Work..
private string _messageId;
public string MessageId { get { return _messageId; }}
public List<T> Data { get { return _data; }}
}
public List<MessageResponse> GetData(List<MessageRequest> requests)
{
List<MesssageResponse> responses = new List<MessageResponse>();
foreach(MessageRequest r in requests)
{
//I will determine the collection type for the response at runtime based
//on the MessageRequest "ServiceMethod"
List<TypeIFiguredOutFromServiceMethod> data = getData();
responses.add(new MessageResponse()
{
MessageId = r.MessageId,
Data<TypeIFiguredOutFromServiceMethod> = data
});
Something like that...
I can't specify the List Type on the MessageResponse class that is this:
public class MessageResponse<T>
{
}
because the collection of MessageRequests will have different operations and thus will require different collection results.
Since you are dealing with messages that most likely come in as strings that you need to parse anyway, I would be inclined to keep them as strings like this:
public class MessageResponse
{
public string MessageId { get; private set; }
public Type MessageType { get; private set; }
public List<string> Data { get; private set; }
}
If your code has already performed the parsing then change string to object and go with that.
As it would turn out this topic has been talked about a few times on SO. I am going to post what I did so hopefully someone can benefit from this (or even someone gives me a better way of accomplishing this).
The intent of my implementation was to pass into a Service Manager object a collection of request objects; with each request object specifying an Operation and any additional parameters required for that operation.
My service implementation would then fetch a response for each request object received - the response data would vary in type - the determinant being the operation specified in the request. That is if I have an operation that is "GetCatalog", the result from that request would be a List<Items>. Conversely a "GetAddressbooks" would yield List<AddressbookRecords>.
This is where I needed a generic property on a class. My Message response object would have a generic List as a property.
In the end I ended up using a combination of #Mihai Caracostea suggestion to use object and the solution posted here.
First I modified the MessageRequest and MessageResponse objects both for clarity and efficiency:
public class MessageRequest
{
private readonly string _messageId;
private readonly Operation _operation;
public MessageRequest(string id, Operation operation)
{
_messageId = id;
_operation = operation;
}
public string MessageId { get { return _messageId; } }
public Operation Operation { get { return _operation; } }
}
public class MessageResponse
{
private object _data;
public MessageRequest Request { get; set; }
public T Data<T>()
{
return (T)Convert.ChangeType(_data, typeof(T));
}
public void SetData(object data)
{
_data = data;
}
}
The MessageResponse definition really enables this. Using the getter / setter approach to the property - I use the Object _data field to set the data received from a backing service and the T Data to basically cast the data to what it should be when the client receiving the MessageResponse object reads the data.
So the Service Manager Implementation looks like this:
public List<MessageResponse> GetData(List<MessageRequest> messageRequests)
{
List<MessageResponse> responses = new List<MessageResponse>();
try
{
foreach (MessageRequest request in messageRequests)
{
//Set up the proxy for the right endpoint
SetEndpoint(request);
//instantiate a new Integration Request with the right proxy and program settings
_ir = new IntegrationRequest(_proxy, ConfigureSettings(request));
MessageResponse mr = new MessageResponse { Request = request };
using (IntegrationManager im = new IntegrationManager(_ir))
{
mr.SetData(GetData(im, request));
}
responses.Add(mr);
}
return responses;
}//
catch (Exception)
{
throw;
}
The client implementation consuming the result of the GetData method looks like:
List<MessageRequest> requests = new List<MessageRequest>();
requests.Add(new MessageRequest(Guid.NewGuid().ToString(), Operation.GetBudgets));
requests.Add(new MessageRequest(Guid.NewGuid().ToString(), Operation.GetCatalogItems));
List<MessageResponse> responses;
using (ServiceManager sm = new ServiceManager())
{
responses = sm.GetData(requests);
}
if (responses != null)
{
foreach (var response in responses)
{
switch (response.Request.Operation)
{
case Operation.GetBudgets:
List<Budget> budgets = response.Data<List<Budget>>();
break;
case Operation.GetCatalogItems:
List<Item> items = response.Data<List<Item>>();
break;
}
}
}
This is just a test - but basically I constructed two MessageRequest objects (get budgets, and get catalog items) - posted to the Service and a collection of the MessageResponse objects returned.
This works for what I need it to do.
Two additional points I want to mention on this subject are one I looked a using reflection to to determine the response types at runtime. The way I was able to to do it was by specifying a custom attribute type on the operation enum:
public enum Operation
{
[DA.Services.ResponseType (Type = ResponseType.CreateOrder)]
CreateOrder,
[DA.Services.ResponseType(Type = ResponseType.GetAddressbooks)]
GetAddressbooks,
[DA.Services.ResponseType(Type = ResponseType.GetCatalogItems)]
GetCatalogItems,
[DA.Services.ResponseType(Type = ResponseType.GetAddressbookAssociations)]
GetAddressbookAssociations,
[DA.Services.ResponseType(Type = ResponseType.GetBudgets)]
GetBudgets,
[DA.Services.ResponseType(Type = ResponseType.GetUDCTable)]
GetUDCTable
}
class ResponseType : System.Attribute
{
public string Type { get; set; }
public const string CreateOrder = "Models.Order";
public const string GetAddressbooks = "Models.AddressbookRecord";
public const string GetCatalogItems = "Models.Item";
public const string GetAddressbookAssociations = "Models.AddressbookAssociation";
public const string GetBudgets = "Models.Budget";
public const string GetUDCTable = "Models.UdcTable";
}
I basically looked at using Activator.CreateType() to dynamically create the response object for the client by evaluating the ResponseType.Type on the operation specified in the request.
While this was elegant - I found it was not worth the time expense to process. This implementation has fairly well defined objects that haven't changed in years. I am willing to write a switch statement to cover all scenarios rather than using reflection for the flexibility. The reality is I just don't need the flexibility in this particular instance.
The second point I want to mention (just for anyone that reads this) edification is "Why" a generic cannot be used as a class property. As it would turn out this was also debated. There were arguments that went from "it doesn't make sense" to "microsoft felt it was too hard to do in the release and abandoned it". Those discussions can be found here and here.
In the end one of those threads provided a link to a technical reason. That reason being the compiler would have no way of determining how much memory to allocate for an object that has a generic property. The author of the article was Julian Bucknail and can be found here.
Thank you to everyone that posted suggestions in finding my solution.
I am trying to figure out something with c# code, and I'm not 100% sure if it is possible, but I am trying to implement search functionality for several classes which is streamlined and overall easy to develop for. Right now I have the following code:
[DataContract(IsReference = true), Serializable]
public class ClassSearch
{
[DataMember]
public string Name { get; set; }
[DataMember]
public object Value { get; set; }
public override string ToString()
{
return String.Format("{0} = {1}", Name, Value);
}
... // additional logic
}
However, I would like to include strong typing for the object value so that it only can be set to the property that is passed in, I guess like similar (hypothetical, not sure if this would work)
[DataContract(IsReference = true), Serializable]
public class ClassSearch<TProperty>
{
[DataMember]
public TProperty Property {get; set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
... // additional logic
}
public class MainClass
{
public void Execute()
{
SomeClass someClass = new Class{
Property = "Value";
};
ClassSearch search = new ClassSearch<SomeClass.Property>{
Property = someClass.Property
};
var retString = search.ToString(); // Returns "Property = 'Value'"
}
}
It seems you are trying to create a WCF service to be able to pass any type you like.
First of all, this is not WSDL-friendly. All WCF services needs to be able to be exposed in WSDL. WSDL is all about well-defined contracts hence the types need be all defined. So that generic approach would not work - mainly because of WSDL. Having said that, you still can use generics but then you have to use KnownType and actually define all the types possible - which for me defeats the object.
Yet, one thing you can do is to serialize the object yourself and pass around with its type name across the wire. On the other side, you can pick it up deserialize.
So something along the line of:
// NOTE: Not meant for production!
[DataContract]
public class GenericWcfPayload
{
[DataMember]
public byte[] Payload {get; set;}
[DataMember]
public string TypeName {get; set;}
}
If there are no easier answers I would try it with this one.
You could use expressions like so:
// Sample object with a property.
SomeClass someClass = new SomeClass{Property = "Value"};
// Create the member expression.
Expression<Func<object /*prop owner object*/, object/*prop value*/>> e =
owner => ((SomeClass)owner).Property;
// Get property name by analyzing expression.
string propName = ((MemberExpression)e.Body).Member.Name;
// Get property value by compiling and running expression.
object propValue = e.Compile().Invoke(someClass);
You hand over your property by the member expression owner => ((SomeClass)owner).Property. This expression contains both information you need: property name and property value. The last two lines show you how to get name and value.
Following a larger example:
class MainClass
{
public static void Execute()
{
SomeClass someClass = new SomeClass{
Property = "Value"
};
var search = new ClassSearch(s => ((SomeClass)s).Property);
Console.Out.WriteLine("{0} = '{1}'", search.Property.Name, search.Property.GetValue(someClass));
}
}
class Reflector
{
public static string GetPropertyName(Expression<Func<object, object>> e)
{
if (e.Body.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException("Wrong expression!");
}
MemberExpression me = ((MemberExpression) e.Body);
return me.Member.Name;
}
}
class ClassSearch
{
public ClassSearch(Expression<Func<object, object>> e)
{
Property = new PropertyNameAndValue(e);
}
public PropertyNameAndValue Property { get; private set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
}
class PropertyNameAndValue
{
private readonly Func<object, object> _func;
public PropertyNameAndValue(Expression<Func<object, object>> e)
{
_func = e.Compile();
Name = Reflector.GetPropertyName(e);
}
public object GetValue(object propOwner)
{
return _func.Invoke(propOwner);
}
public string Name { get; private set; }
}
class SomeClass
{
public string Property { get; set; }
}
The main part of that example is the method Reflector.GetPropertyName(...) that returns the name of a property within an expression. I.e. Reflector.GetPropertyName(s => ((SomeClass)s).Property) would return "Property".
The advantage is: This is type-safe because in new ClassSearch(s => s.Property) compiling would end with an error if SomeClass would not have a property 'Property'.
The disadvantage is: This is not type-safe because if you write e.g. new ClassSearch(s => s.Method()) and there would be a method 'Method' then there would be no compile error but a runtime error.