This error comes as result of This previous question. I'm trying to call a polymorphic method from WCF client. This is my contract:
public interface IOhmioService
{
[OperationContract]
IEnumerable<Enumerador> GetEnumerador<T>() where T : IEnumerador, new();
}
This is my class implementation:
public class OhmioService : IOhmioService
{
public IEnumerable<Enumerador> GetEnumerador<T>() where T : IEnumerador, new()
{
T _obj = new T();
return _obj.Enumerar();
}
}
And call it from client like this:
public IEnumerable<Enumerador> Clients { get; set; }
Clients = this.serviceClient.GetEnumerador<Clientes>();
If i call this method from within the class everything works fine. But if i call it from WCF client a get this error:
The non generic Method 'Ohmio.Client.OhmioService.OhmioServiceClient.GetEnumerador()'
cannot be used with types arguments
What i'm i doing wrong? Thanks!
UPDATE
Ok. I try suggested solution, and get this Horrible error:
Type 'System.RuntimeType' wasn't spected with the contract name RuntimeType:http://schemas.datacontract.org/2004/07/System'. Trye to use DataContractResolver or add the unknown types staticaly to the list of known types (for instance, using the attribute KnownTypeAttribute or adding them to the list of known types to pass to DataContractSerializer)
Maybe using generic types over wcf is not such a good idea after all. I was trying to reduce repetitive code on the WCF service.
You cannot have generic OperationContract methods in a WCF ServiceContract. See here for further details: WCF. Service generic methods
You need to pass the type as a method parameter:
public interface IOhmioService
{
[OperationContract]
IEnumerable<Enumerador> GetEnumerador(string typeName);
}
public class OhmioService : IOhmioService
{
public IEnumerable<Enumerador> GetEnumerador(string typeName)
{
var type = Type.GetType(typeName);
var _obj = (IEnumerador)Activator.CreateInstance(type);
return _obj.Enumerar();
}
}
UPDATE
See update above; pass the fully qualified name of the type. That won't cause a serialization issue.
Related
I'm trying to create an abstract proxy for several interfaces. Obviously both a concrete proxy implementation and the concrete proxied class it 'fronts' must implement the same interface. The proxy accepts the proxied class (to proxy to). Ideally I wouldn't constrain the interfaces at all but I don't believe C# allows constraining a generic type to being an interface. As such, my sample below uses IProxiableInterface to enforce.
Here's some sample code that all appears fine except for this problem:
Without the parent class, Rider complains "'T': type name expected"
With the parent class, Rider says "'T': interface name expected".
For both, the compiler says "error CS0689: Cannot derive from 'T' because it is a type parameter"
Both of them allow the concrete proxy to fail to implement the interface.
abstract class AbstractProxy<T> : /*MonoBehaviour,*/ T // <-- Error: "'T': type name expected" or "'T': interface name expected"
where T : IProxiableInterface
{
protected T impl;
public AbstractProxy(T impl) {
this.impl = impl;
}
}
interface IProxiableInterface {}
interface IFriendly : IProxiableInterface {
string sayHi();
}
sealed class HiSayer : IFriendly {
public string sayHi() => "Hi";
}
sealed class HiProxy : AbstractProxy<IFriendly> {
public HiProxy(IFriendly impl) : base(impl) {}
public string sayHi() => impl.sayHi(); // <-- _should_ be an error when omitted but not because the interface constraint is ignored
}
sealed class User {
public User() {
IFriendly friendlyToBeProxied = new HiSayer();
IFriendly friendlyProxy = new HiProxy(friendlyToBeProxied);
Console.WriteLine(friendlyProxy.sayHi());
}
}
So it seems C# disallows this approach (which I learnt after typing all of this into StackOverflow and getting hinted with this question :) ).
For now I've had to remove the constraint on AbstractProxy so it doesn't have to implement the interface. As a workaround I've added an assertion to a factory method that takes an extra generic type indicating the type being built:
Assert.IsTrue(typeof(T1).IsAssignableFrom(typeof(T2)), "T2 \"{1}\" must implement T1 \"{2}\" for {0}", go, typeof(T2), typeof(T1));
So what's a better solution The Right Way to solve this, please?
This is the kind of scenario that requires meta-programming; specifically, you need to implement a specific interface only known at runtime, which isn't something you can express against a pre-compiled type. Typically, you would end up using TypeBuilder to create a new type at runtime, implementing the type you need, and then using reflection to inspect the interface you want looking for the members you need, adding those onto your new type (MethodBuilder etc), and writing an implementation (ILGenerator) that invokes whatever proxy logic you need (which may involve writing a constructor via ILGenerator that takes the proxy instance as a parameter and stores it in a field, then access the field in each method for the proxy step). You'd then create the concrete type, and store that somewhere as a cache (because all this TypeBuilder work is expensive). This is a lot of work! As a starting point: here's the proxy emitter for protobuf-net.Grpc
Looks like you want your AbstractProxy to use composition rather than inheritance, so you don't need it to derive from anything:
abstract class AbstractProxy<T> where T : IProxiableInterface
{
protected T impl;
public AbstractProxy(T impl)
{
this.impl = impl;
}
}
IProxiableInterface defines no behaviour so it seems that you are using it simply to constrain the generic types.
This would then be fine:
sealed class HiProxy : AbstractProxy<IFriendly>
{
public HiProxy(IFriendly impl) : base(impl) {}
public string sayHi() => impl.sayHi();
}
Please suppose I have the following classes and interfaces:
public class ConcreteRepository : IRepository<T>, IEntityOwner
{ }
public interface IRepository<T>
{ }
public interface IEntityOwner
{ }
public class SomeModel
{ }
and suppose I have registered the following service in my Asp.Net Core 2.0 startup class:
services.AddScoped<IRepository<SomeModel>, ConcreteRepository>();
I can get the instance of ConcreteRepository like this:
var concreteRepositoryInstance =
httpContext.RequestServices.GetService(typeof(IRepository<SomeModel>))
as IRepository<SomeModel>;
How can I get the instance of ConcreteRepository by the type of ConcreteRepository?
I imagine something like this:
var concreteRepositoryInstance =
httpContext.RequestServices.GetService(typeof(ConcreteRepository))
as IEntityOwner;
Please note that I cannot use any generics to answer my question, because my use case refers to a custom attribute that takes the type of concreteRepository as an input parameter (and attributes cannot be generics by design).
What I tried so far:
(a) I checked and tried all httpContext.RequestServices.GetService... methods but they all require the type of interface with which the concrete type is registered with.
(b) I was thinking about getting all services from the dependency container, but IServiceProvider does not offer getting all services. I can only get them by the type of interface.
Try registering type directly like so
public void ConfigureServices(IServiceCollection services)
{
// container will create the instance of this type
services.AddScoped<ConcreteRepository>();
}
Then you will be able to resolve type directly with
var concreteRepositoryInstance =
httpContext.RequestServices.GetService(typeof(ConcreteRepository))
as IEntityOwner;
I have a WCF service.
[ServiceContract(ConfigurationName="WebEntityService")]
[ServiceKnownType(typeof(WcfEntityService.TH.Category))]
public interface IEntityService {
[OperationContract(IsOneWay=true)]
void ScanEntity(ScanInfo scanInfo, WebEntityBase entity);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class EntityService : IEntityService {
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void ScanEntity(ScanInfo scanInfo, WebEntityBase entity) {
try {
WebScanner webScanner = new WebScanner(entity);
webScanner.Scan(scanInfo);
}
catch (Exception) {
throw;
}
}
}
The WcfEntityService.TH.Category class is inherited from WebEntityBase and placed in a different assembly. This class has the service reference to the WCF service and it calls ScanEntity recursively.
The problem is following.
When the WcfEntityService.TH.Category class calls ScanEntity I occur a serialization error.
Type 'WcfEntityService.TH.Category' with data contract name 'Category:http://schemas.datacontract.org/2004/07/WcfEntityService.TH' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
Can anybody say there is any way to solve this issue?
I have a WCF service with an operation contract that returns null values. That is: it's supposed to return some custom class 'ProgressReport', but in the client application it shows up as null. In the WCF service itself the custom class is instantiated and returned without errors and without becoming null at any time.
The 'ProgressReport' class is not defined as DataContract because it is defined in another assembly.
For the operation that returns 'ProgressReport', the WcfTestClient informs me that it cannot perform operation because it uses type 'ProgressReport'.
I've tried adding an operationcontract with System.Object as return type, but it gives me the same error (cannot perform operation because it uses type 'System.Object')
Does anyone know how to solve this?
You could try to extend the ProgressReport-class (if it's not sealed) and define that as a DataContract (but I think that does not help with the properties of the class as they needed to be marked as DataMembers) or create a own class as a kind of a proxy and return this object:
[DataContract]
public class ProgressReportWcf : ProgressReport
{
}
or
[DataContract]
public class ProgressReportWcf
{
[DataMember]
public int Id { get; set; }
//aso...
public ProgressReportWcf(ProgressReport report)
{
Id = report.Id;
//aso...
}
}
I'm trying to create a webservice to return a generic. The return class looks like this:
[Serializable]
public class RenderReturn
{
public RenderReturnStatus StatusReturn { get; set; }
public string MessageReturn { get; set; }
public string MessageTitle { get; set; }
public object **ObjectReturn** { get; set; }
}
Where ObjectReturn can be an object or a list of application objects, like cars, customers, etc..
But the webservice returns the following error:
System.InvalidOperationException: There was an error generating the XML document. --->
System.InvalidOperationException: The type Environment was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
This is possible or method should always return specific types?
Explicitly name your types. Otherwise one can put something in that isn't serializable.
Try something along these lines:
public class RenderReturn<T>
{
public T ObjectReturn {get;set;}
}
That way, at run-time, you'll have a concrete type rather than just System.Object.
Type of object is too generic for .NET to know what kind of object it is dealing with and how to deserialise. So it asks you to give it some hint by using XmlInclude attributes telling .NET the types to expect. In WCF you do the same: you use KnownType attribute to decorate properties.
Type object is not a good candidate for DTO objects that need to cross process boundaries.
In WCF or Web Services, try not to think in object-oriented fashion but think in WSDL. As far as WSDL is concerned you have a contract which explicitly defines the type of messages passed between client and server.