I'm looking for the best method of doing this.
I have a series of data types which I want to return in the WCF, under one method. This is why I have a MarkerInterface, so that I don't need 100s of ServiceContracts/Methods to just simply transform the data.
The unfortunate part is, all the DataContracts (such as currentbatch) are all unique, they have their unique set of properties. The reason I have a Transformer is that they all require some sort of Data Transformation based off of the dataset.
The transformer interface is as follows:
public interface IDataTransformer
{
IMarkerInterface Transform(DataSet inDataSet_);
}
Then i have a transformer library for each datacontract (which i will explain below)
public class CurrentBatch_Transformer : IDataTransformer
{
}
This is One of the many datacontracts i will have, that implement IMarkerInterface.
[DataContract]
public class CurrentBatch : IMarkerInterface
{
[DataMember]
public string GroupName { get; set; }
[DataMember]
public bool FlagLocked { get; set; }
}
So, because i have an IMarkerInterface; I can place everything in one method (GetDataUsingDataContract), and take in their respective transformer and a DataSet.
public IMarkerInterface GetDataUsingDataContract(IDataTransformer composite, DataSet inData_)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
return composite.Transform(inData_);
}
Again, my questions are:
1) Is this a good practice? If this isn't; why, and is there a better way of doing it?
2) Will the Interface get serialized during the WCF serialization? (I don't want it to get serialized, but wouldn't mind if it did).
Yes, it's acceptable solution, but you must let WCF know what kind of types you are going to use, because it should form WSDL document. You can use either ServiceKnownType attribute for ServiceContract, KnownType for data contract or add known types in config.
Here are examples:
ServiceContract:
[ServiceKnownType("GetKnownTypes", typeof(Helper))]
[ServiceContract()]
public interface IService
{
[OperationContract]
IMarkerInterface GetMarker();
}
static class Helper
{
static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
return new Type[] { typeof(CurrentBatch) };
}
}
KnownType:
[DataContract]
[KnownType("GetKnownType")] //there are few option of usage, you can apply for one concrete class: [KnownType(typeof(InheritedClass))]
public class BaseClass
{
private static Type[] GetKnownType()
{
return return new Type[] { typeof(InheritedClass) };;
}
}
Config file:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="MyProject.IMarkerInterface, MyProjectAssembly">
<knownType type="MyProject.CurrentBatch, MyProjectAssembly"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
Related
I'm following the tutorial on this site which talks about using the Castle DictionaryAdapterFactory and an interface to access an applications app.setting keys without using strings throughout your code.
The way it works is you define an Interface that has the key names for your app.settings
public interface ISettings
{
string dog { get; }
string cat { get; }
}
Then use the DictionaryAdapterFactory to do the coding between the interface and your app.settings dictionary.
var factory = new DictionaryAdapterFactory();
var settings = factory.GetAdapter<ISettings>(ConfigurationManager.AppSettings);
Now you can access the values like this:
settings.dog
settings.cat
My question is, is it possible to have something more than a complicated than a simple getter. For example, can I tell DictionaryAdapterFactory to use a decryption method on the value of one of the keys and then return that instead of the key value?
I'm assuming that this is not possible since you can't define methods in an interface, but wanted to see if there was another way that I was missing.
You can use a wrapper class to wrap your interface with a class that implements custom methods.
You add [AppSettingWrapper] over your interface:
[AppSettingWrapper]
public interface ISettings
{
string dog { get; }
string cat { get; }
}
The AppSettingWrapper class is defined in the class below and lets you do what you want in the getter and setting.
public class AppSettingWrapperAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder, IPropertyDescriptorInitializer, IDictionaryPropertyGetter
{
public string GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property)
{
return key;
}
public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, object storedValue, PropertyDescriptor property, bool ifExists)
{
return storedValue;
}
public void Initialize(PropertyDescriptor propertyDescriptor, object[] behaviors)
{
propertyDescriptor.Fetch = true;
}
}
Most of this solution comes from https://gist.github.com/kkozmic/7858f4e666df223e7fc4.
I have a ServiceStack 3-based client-server architecture. I'm trying to create a service whose request DTO contains a property with an abstract type, with two different concrete classes implementing it. The abstract type could be either an abstract class or an interface; however, in either case, the server receives a null object in the property.
There's three assemblies and corresponding namespaces: TestClient, Server, and CommonLib referenced by both client and server.
That is, spread across the three assemblies:
namespace CommonLib.Services
{
public class GetThing : IReturn<GetThingResponse> // request DTO
{
public IThisOrThat Context { get; set; }
}
public class GetThingResponse
{
public Dictionary<int, string> Result { get; private set; }
public GetThingResponse(Dictionary<int, string> result) // response DTO
{
Result = result;
}
}
}
namespace CommonLib
{
public interface IThisOrThat { }
public class This : IThisOrThat { } // and so forth
}
namespace Server.Services
{
public class GetThing Service : IService
{
public object Get(GetThing request)
{
var foo = request.Context; // this is null
}
}
}
namespace TestClient
{
class Program
{
public const string WSURL = "http://localhost:61435/";
static void Main(string[] args)
{
using (var client = new JsonServiceClient(WSURL))
{
var result = client.Get(new GetThing
{
Context = new CommonLib.This("context info")
});
}
}
If I change the Context property in GetThing to be of type This instead of IThisOrThat, this works. Leaving it as the interface, or changing IThisOrThat to be an abstract class, results in the data being transmitted as null.
I'm assuming this is a serialization problem. I've tried changing the interface to an abstract class and decorating that with appropriate KnownType attributes, but ServiceStack's serializer doesn't appear to benefit from this. Is there any trick to get this done?
You would need to enable JsConfig.IncludeTypeInfo = true; on the client side, so the serializer includes the type information with the request. This will add an extra property (__type) with the type definition so the service knows what to type it as.
It fails currently because requests by default don't provide type information to deserialize the object into the class that implements the interface. This was an issue that was previously raised.
The problem is the when the JSON client makes the request, it will serialize up the a class that implements IThisOrThat such as your This class. But when it gets to the other end ServiceStack.Text doesn't know what to deserialize the object into. The type information is lost so it doesn't know what kind of IThisOrThat it is. So without the additional __type information property in the request this is happening:
Scenario:
interface ISomething
{
string Name;
}
class MySomething : ISomething
{
public string Name { get; set; }
public int Age { get; set; }
}
class MySomethingElse : ISomething
{
public string Name { get; set; }
public int Size { get; set; }
}
Then you make the call from your JsonServiceClient using a typed object
client.Get(new MySomething { Name: "Duck", Age: 20 });
The JSON that is sent would be { "Name":"Duck", "Age":20 } what type does the deserialiser choose now? It could be an MySomething or a MySomethingElse, or even another ISomething that it just doesn't know about yet. So because it can't decide the result is simply null.
Generally interfaces and DTOs don't mix, see here.
I had a similar problem, and realized i didn't have { get; set; } applied to the response DTO, so the result of my object was always null...
Thought this information could also help anyone searching for this ...
We have the following classes and WCF service (using protobuf-net for serialization):
[DataContract]
[KnownType(typeof(NamedViewModel))]
public class NamedViewModel<TKey> : IViewModel
{
[DataMember]
public virtual TKey Id { get; set; }
[DataMember]
public virtual string Name { get; set; }
}
[DataContract]
[KnownType(typeof(ScheduleTemplateViewModel))]
public class NamedViewModel : NamedViewModel<int>
{
}
[DataContract]
public class ScheduleTemplateViewModel : NamedViewModel
{
[DataMember]
public string Comment { get; set; }
}
[DataContract]
public class Container
{
[DataMember]
public IEnumerable<ScheduleTemplateViewModel> Templates { get; set; }
}
[ServiceContract]
public interface IService
{
[OperationContract]
Container Get();
}
public class Service : IService
{
public IEnumerable<Container> Get()
{
return new Container { Templates = Enumerable.Range(1, 10)
.Select(i => CreateTemplate()).ToArray() };
}
private void ScheduleTemplateViewModel CreateTemplate()
{
var instance = WindsorContainer.Resolve<ScheduleTemplateViewModel>();
// populate instance
return instance;
}
}
We have two problems:
We get an exception during serialization that the Castle DynamicProxy type for ScheduleTemplateViewModel is unexpected. We noticed that there is custom code in protobuf-net to handle NHibernate and EntityFramework proxies...but not Castle DynamicProxies. We worked around this by adding an additional case statement in the protobuf-net source code to check for Castle's IProxyTargetAccessor type...but it would be nice if there were a way of handling this without modifying the protobuf-net source code...
Members on ScheduleTemplateViewModel (namely Comment) are serialized correctly...but base class Members are not. We already have the InferTagFromNameDefault set to true on RuntimeTypeModel.Default.
I can add that; can you tell me the full name (including namespace) of that interface?
From the example you give, none of those values should serialize, as none of them include the necessary numeric field-number information. Since you say some do serialize, I'm going to assume that this is an omission in the copy/paste. Protobuf-net will try to use the Order=n information from [DataMember(...)] if nothing better is available. However, if must be emphasized that protobuf-net cannot use [KnownType(...)], and inheritance again needs some explicit numeric field-number information. This is most easily added via [ProtoInclude(...)], but can also be provided at runtime
Suppose I have an Interface with some properties:
public interface IDummy
{
string First {get;set;}
string Second {get;set;}
string Third {get;set;}
string Fourth {get;set;}
}
Now, I have a class which implements that interface:
public class DummyClass: IDummy
{
// ...
}
Is it possible, not to implement the interface properties explicitly and instead use DynamicObject? For example:
public class DummyClass: DynamicObject, IDummy
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Get the value from a Config file or SQLite db or something
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// Get the value to a Config file or SQLite db or something
}
}
I am just curious if this is possible or not?
Thanks.
No, this is not possible.
If you are implementing an interface, you need to implement all of its members. C# is still a statically typed language, after all.
When you say a type implements an interface, you are saying it conforms to its contract. Not implementing all of the members means that you are not complying with the contract.
The compiler would see your code and will not assume that you have implemented the contract correctly (in a dynamic fashion) - it will fail to compile.
No, basically. An interface is for static typing; to satisfy an interface your type must actually provide a regular (non-dynamic) implementation. You could not claim to implement it (IDummy), and detect the names, but that could relate to any interface that uses those same names, not just IDummy.
You could make a wrapper.
class DummyWrapper : IDummy
{
private readonly DynamicObject _wrapped;
public DummyWrapper(DynamicObject wrapped)
{
_wrapped = wrapped;
}
string First
{
get { return _wrapped.First; }
set { _wrapped.First = value; }
}
string Second
{
get { return _wrapped.Second; }
set { _wrapped.Second = value; }
}
string Third
{
get { return _wrapped.Third; }
set { _wrapped.Third = value; }
}
string Fourth
{
get { return _wrapped.Fourth; }
set { _wrapped.Fourth = value; }
}
}
You might also be interested in these questions:
Automatically creating a wrapper to implement an interface
Dynamically implementing an interface in .NET 4.0 (C#)
I want to inherit from a class which is located in a WCF Service. The Inheritance works fine (I see the properties of the base class in my child class), my problem occurs when I try to call a method from the service and pass the childtype as a parameter and not the basetype.
Base class in WCF Service (Pet):
[ServiceContract]
public interface IService
{
[OperationContract]
void BringPet(Pet pet);
[OperationContract]
void TakePet(Pet pet);
[OperationContract]
List<Pet> GetAllPets();
}
[DataContract]
public class Pet
{
private string _name;
private string _color;
[DataMember]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember]
public string Color
{
get { return _color; }
set { _color = value; }
}
}
Class on the client (Dog inherits from Pet):
[DataContract()]
class Dog : PetService.Pet
{
[DataMember()]
public bool HasPedigree { get; set; }
[DataMember()]
public string Race { get; set; }
}
When I try calling something like this:
Dog dog = new Dog()
{
Color = "Black",
Name = "Pluto",
HasPedigree = true,
Race = "Travolta"
};
_client.BringPet(dog);
I get a CommunicationException which says that the type Dog is not expected by the method BringPet(Pet pet).
I would solve this problem by setting the KnownType attributes on the service side, but because my service must not know the type Dog I can't set the KnownType or ServiceKnownType attributes.
Can someone help me out?
If you want to have inherited classes that get returned instead of the ones defined in your service contract, you need to make this fact known to WCF by means of the ServiceKnownType attribute:
[ServiceContract]
[ServiceKnownType(typeof(Dog))]
public interface IService
{
[OperationContract]
void BringPet(Pet pet);
[OperationContract]
void TakePet(Pet pet);
[OperationContract]
List<Pet> GetAllPets();
}
This basically tells the WCF service to also allow classes of type Dog to be used in your service.
Or you can decorate your data contract with the KnownType attribute:
[DataContract]
[KnownType(typeof(Dog))]
public class Pet
{
.....
}
to associate your data contract type with additional types that could be used in its place.
One way or the other: you have to make your extra type known to the WCF runtime - WCF cannot figure out that fact by just checking .NET type inheritance.
I think this is very similar to this question: Service - client interface, architecture advice
As you will see, there is no really easy way to do this without making your service operation more generic.