Generic List as Class Property - c#

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.

Related

Is it possible to optimize large switch statements in C#?

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 want to fill class members with default if they are missing, using generic in C#

I have multiple web requests that post JSON object and I have serializable classes with all the fields. For example:
[Serializable]
public class RequestOne()
{
public string date;
public string information;
public string subject;
}
[Serializable]
public class RequestTwo()
{
public int ID;
public string Data;
public string message;
}
And my method takes partially filled request class and I want to fill in any missing fields with default values declared in constant class.
And I want to avoid writing each method with for each request, like :
public static void FillWithDefault(this RequestOne request)
{ if (request.date.Equals(null)) request.date = DEFAULT_DATE;
if (request.information.Equals(null)) request.information = DEFAULT_INFO;
if (request.subject.Equals(null)) request.subject = DEFAULT_SUBJECT;
}
public static void FillWithDefault(this RequestTwo request)
{
//do the same for the fields in RequestTwo
}
I want to know if there is any way to achieve this using generic?
I want to do something similar to this:
public static void FillWithDefault<T>(this T request)
{
if(typeof(T) == typeof(request))
{
//check each member in request and fill with default if it's null
}
.
.
.
}
So that in my main method I can use like this :
RequestOne request = new RequestOne();
request.FillWithDefault();
RequestTwo request2 = new RequestTwo();
request2.FillWithDefault();
Can someone please help with idea on this? Am I overthinking on this? I'm new to generic so please feel free to advise on my code.
Edit
Sorry guys, I did not mention that I will be using this method for test automation. Those request contracts cannot be changed since it's by design. Sorry again for the confusion!
Use constructors. Also make use of properties. Don't gather the default filling code to one place, it's the responsibility of the classes so keep them there.
[Serializable]
public class RequestOne()
{
public string date { get; set; };
public string information { get; set; };
public string subject { get; set; };
public RequestOne()
{
Date = DEFAULT_DATE;
Information = DEFAULT_DATE;
Subject = DEFAULT_SUBJECT;
}
}
[Serializable]
public class RequestTwo()
{
public int ID { get; set; };
public string Data { get; set; };
public string Message { get; set; };
public RequestTwo()
{
Data = DEFAULT_DATA;
message = DEFAULT_MESSAGE;
}
}
Generics are used when the types have common operations/properties defined so you can apply the same routine for each type in one place instead of declaring different methods for each type.
However in this case, you have two different types with different properties, so I would not use generics here. You can achieve it with manual type checking and using reflection to get properties and set them but it's not a good way and definitely wouldn't be a good usage of generics.
Overloading is the way to go.
you can use property
[Serializable]
public class RequestOne()
{
private string _date;
public string date { get { return _date;} set { _date = value ?? DEFAULT_DATE; }};
public string information; // same here
public string subject; //same here
}

C# System.Collections.Generic.Dictionary`2.Insert - An item with the same key has already been added

This question is in regards to a .Net Framework 4.5 MVC Web Application.
I've got a block of code that we've inherited and been using for years that generically converts a DataTable to a List<T>, and one of the private methods gets a list of the properties for a generic class, for example:
ORIGINAL CODE
private static Dictionary<Type, IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();
public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);
//get types
if (!typeDictionary.ContainsKey(typeof(T)))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}
//return
return typeDictionary[type];
}
Nothing incredibly exciting going on there, it's just making sure the typeDictionary doesn't already contain the key (type) and adds it to the dictionary (key=type, value=properties), so we can access them later.
We use this code generically for any kind of "model" object, but for this particular example, this is the one that's given me trouble on 2 different occasions.
MODEL OBJECT
public class GetApprovalsByUserId
{
// constructor
public GetApprovalsByUserId()
{
TicketId = 0;
ModuleName = string.Empty;
ModuleIcon = string.Empty;
ApprovalType = string.Empty;
VIN = string.Empty;
StockNumber = string.Empty;
Year = 0;
Make = string.Empty;
Model = string.Empty;
Services = string.Empty;
RequestedDate = DateTime.MinValue;
}
// public properties
public int TicketId { get; set; }
public string ModuleName { get; set; }
public string ModuleIcon { get; set; }
public string ApprovalType { get; set; }
public string VIN { get; set; }
public string StockNumber { get; set; }
public int Year { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public string Services { get; set; }
public DateTime RequestedDate { get; set; }
}
Again, nothing really significant going on in that particular model class, and nothing any different than we use in any other class.
Like I said, we use this code generically in several projects, and have never once had issues with it, but on 2 separate occasions in the past day we've had it throw the following exception:
An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Utilities.Extensions.GetPropertiesForType[T]()
at Utilities.Extensions.ToObject[T](DataRow row)
at Utilities.Extensions.ToList[T](DataTable table)
In case it is helpful, you can see the full Extensions.cs class (static) that the extension methods live in here:
https://pavey.azurewebsites.net/resources/Extensions.txt
My questions are:
Given the fact that the code is already doing a !typeDictionary.ContainsKey(typeof(T)) check, how is it possible that it could ever pass that test, yet fail on the typeDictionary.Add(type, type.GetProperties().ToList()); call?
Why would it be so sporadic? It seemingly works 99% of the time, using the same code, the same class (GetApprovalsByUserId, shown above), and never has failed otherwise in any other project or any other model class.
We have not been able to reproduce this issue using the exact same code, model, data, or otherwise the exact same setup in any environment, so not sure how to safe-guard this code anymore than it already is.
One thought I have is to change the code to this:
PROPOSED CODE CHANGE
private static Dictionary<Type, IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();
public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);
IList<PropertyInfo> properties = null;
//get types
try
{
if (!typeDictionary.ContainsKey(type))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}
}
catch
{
}
// try get value
typeDictionary.TryGetValue(type, out properties);
// return
return properties;
}
But since I can't reproduce the error in the first place, I'm not entire sure if this is bullet proof either. My thinking would be that it's just something weird with ContainsKey, particularly with using a typeof(T) as the "key", which allows it to pass the test in odd cases, when it really shouldn't, but the Add fails because it knows the key is already there. So if I try/catch it, if the ContainsKey incorrectly tells me it's not there, when it in fact is, the Add will still fail, but I'll catch it, and move on, and then I can TryParse to get the value out, and all should be well.
Appreciate any thoughts, ideas, or specifically how to reproduce the problem with the Original Code shown above, and recommended improvements to safe guard it.
The problem you have is concurrent access. Between the check and the insert into the dictionary, another thread has come in and added the type, causing the second insert to fail.
To fix this, you have two options: either use locks (as mentioned in the other answers) or use a ConcurrentCollection:
using System.Collections.Concurrent;
private static ConcurrentDictionary<Type, IList<PropertyInfo>> typeDictionary = new ConcurrentDictionary<Type, IList<PropertyInfo>>();
public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);
typeDictionary.TryAdd(type, type.GetProperties().ToList());
//return
return typeDictionary[type];
}
This will add the value if it doesn't yet exist and return true, otherwise it will not do anything and return false
You need an object to lock on:
private object lockObj = new object();
And then you need to lock before adding a key:
if (!typeDictionary.ContainsKey(typeof(T)))
{
lock(lockObj)
{
if (!typeDictionary.ContainsKey(typeof(T)))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}
}
}
This will make any other threads that are looking for the same key wait if it's already in the process of being added. You check ContainsKey again inside the lock because when a stopped thread finally acquires the lock another thread might have already inserted the key.
This is an example of double check locking

Need help deciding how to structure a C# application that creates products that share similarities but have their differences

I'm having a bit of a mental block trying to figure out the best architecture for this program and need some help.
I'm writing a C# application that creates what we'll call "Views". A view is basically an object which accepts some data as input and spits out another object as output.
Here is the code I'm envisioning:
ViewResponse response;
ViewRequest request;
request = new CustomerViewRequest();
request.Translations = GetTranslations(); // generic to Request
request.CustomerViewAsOfDate = new DateTime(2014,1,1); // specific to CustomerViewRequest
response = ViewCreator.CreateView(request);
Console.WriteLine(response.ViewCreatedSuccessfully); // generic to Response
Console.WriteLine((CustomerViewResponse)response.SomeCustomerViewSpecificProperty); // specific to CustomerViewResponse
request = new BKLedgerViewRequest();
request.Translations = GetTranslations(); // generic to Request
request.EAAnalysisData = GetEAAnalysisData(); // specific to BKLedgerViewRequest
response = ViewCreator.CreateView(bkRequest);
Console.WriteLine(response.ViewCreatedSuccessfully); // generic to Response
Console.WriteLine((BKLedgerViewResponse)response.SomeBKLedgerViewSpecificProperty); // specific to BKLedgerViewResponse
You should never need help deciding on a Design Pattern.
The reason, a Design Pattern isn't meant to be a cookie cutter or a one pattern fits all. A pattern should be implemented to solve a particular problem. It shouldn't be used as raw architecture, but to help solve a particular issue.
Once you introduce a pattern, it will introduce complexity and limitations of its own. Which may actually hinder your goal.
The real question should be, how can I refactor this application to optimize performance, capture the application goal, and maintain readability / maintainability?
Based on the information provided, we can't even recommend a pattern because we aren't aware of your applications goals, issues, and limitations. This is why it is often up to the creator to find the optimal solution as you understand your application in a business, user, and developer manner.
As I look at your code, it seems like the key to accomplishing what you want is just to understand object-oriented coding, inheritance, covariance, and contravariance. I did a re-factor of your code below that compiles and generally does what you are looking for based on using a base class for ViewRequest and ViewResponse.
When you instantiate the objects, using the more specific types of CustomerViewRequest (for example) gives you an object that you can treat as either a ViewRequest or a CustomerViewRequest, depending on your needs.
class Class6
{
public object GetTranslations() { return null; }
public object GetEAAnalysisData() { return null; }
public void DoStuff()
{
CustomerViewRequest cvRequest = new CustomerViewRequest();
cvRequest.Translations = GetTranslations(); // generic to Request
cvRequest.CustomerViewAsOfDate = new DateTime(2014, 1, 1); // specific to CustomerViewRequest
CustomerViewResponse cvResponse = ViewCreator.CreateViewResponse<CustomerViewResponse>(cvRequest);
Console.WriteLine(cvResponse.ViewResponseCreatedSuccessfully); // generic to Response
Console.WriteLine(cvResponse.SomeCustomerViewSpecificProperty); // specific to CustomerViewResponse
BKLedgerViewRequest bkRequest = new BKLedgerViewRequest();
bkRequest.Translations = GetTranslations(); // generic to Request
bkRequest.EAAnalysisData = GetEAAnalysisData(); // specific to BKLedgerViewRequest
BKLedgerViewResponse bkResponse = ViewCreator.CreateViewResponse<BKLedgerViewResponse>(bkRequest);
Console.WriteLine(bkResponse.ViewResponseCreatedSuccessfully); // generic to Response
Console.WriteLine(bkResponse.SomeBKLedgerViewSpecificProperty); // specific to BKLedgerViewResponse
}
}
class ViewRequest
{
public object Translations { get; set; }
}
class ViewResponse
{
public bool ViewResponseCreatedSuccessfully { get; set; }
}
class CustomerViewRequest : ViewRequest
{
public DateTime CustomerViewAsOfDate { get; set; }
}
class CustomerViewResponse : ViewResponse
{
public string SomeCustomerViewSpecificProperty { get; set; }
}
static class ViewCreator
{
public static T CreateViewResponse<T>(ViewRequest request)
where T : ViewResponse, new()
{
return new T();
}
}
class BKLedgerViewResponse : ViewResponse
{
public int SomeBKLedgerViewSpecificProperty { get; set; }
}
class BKLedgerViewRequest : ViewRequest
{
public object EAAnalysisData { get; set; }
}

Generic Object Creation Always Returning Nulls

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).

Categories