WCF service creating separate proxy class - c#

I have a WCF service method that sends back a MembershipCreateStatus (System.Web.Security) to the calling method. When I look at the service definition it has recreated the enum as a type of MyProject.MyWebService.MembershipCreateStatus so it is essentially a completely different object.
Is there a way in which I can tell the service definition to use the System.Web.Security class instead, even though it is this within the WCF service?

You you can. You need to use the KnownTypeAttribute class to decorate the DataContract in your WCF Service to specify that the enum is of type System.Web.Security.MembershipCreateStatus I'm not aware of the details of your environment but in general unless you control both the WCF service and the consuming clients, I would carefully research the support requirements and the possibility of a future change to the enum causing backwards compatibility issues with clients that are consuming this enum. Also to consider is a scenario where a non .NET client could consume your WCF service. In that case you need to consider if using the System.Web.Security.MembershipCreateStatus enum is a good idea versus implementing your own statuses for Member creation. Here is another question on StackOverflow with a good discussion on this topic.
For example see the following code below
[ServiceContract]
public interface IMembershipService
{
[OperationContract]
CreateMemberResponse CreateMember(ApplicationUser userToCreate);
}
[DataContract]
[KnownType(typeof(System.Web.Security.MembershipCreateStatus))]
public class CreateMemberResponse
{
[DataMember]
public MembershipCreateStatus Status { get; set; }
}
[DataContract]
public class ApplicationUser
{
public bool ReturnSuccess { get; set; }
public ApplicationUser()
{
ReturnSuccess = true;
}
}
You can write a test against this service as follows and this test will succeed.
[TestClass]
public class MembershipStatusInvocationTests
{
[TestMethod]
public void CreateMemberShouldReturnMembershipCreateStatusEnum()
{
var client = new MembershipServiceClient();
var response = client.CreateMember(new ApplicationUser {ReturnSuccess = true});
Assert.IsInstanceOfType(response.Status, typeof(System.Web.Security.MembershipCreateStatus));
}
}
For more information on the KnownTypeAttribute class see here

Related

Cannot expose mongodb objectId through wcf to mvc

I'm facing an annoying problem while providing a wcf service. I am familiar with wcf and its usage.
Service Implementation:
public class Service : IService
{
public SampleClass SampleMethod ( SampleClass sampleParameter )
{
return new SampleClass { MyProperty1 = Guid.NewGuid(), MyProperty2 = ObjectId.GenerateNewId() };
}
}
Service interface:
[ServiceContract]
public interface IService
{
[OperationContract]
SampleClass SampleMethod ( SampleClass sampleParameter );
}
And my contract class:
/// this class is in DataContracts dll - meantioned in the exception
[DataContract]
public class SampleClass
{
[DataMember]
public Guid MyProperty1 { get; set; }
[DataMember]
public ObjectId MyProperty2 { get; set; }
}
I keep the interface and the contracts in seperate library projects and use the dlls at the clients.
MVC Side calling of service:
static IService Service = new ChannelFactory<IService>(new BasicHttpBinding("regularBinding"), new EndpointAddress(BaseAddress + "Service.svc")).CreateChannel();
public ActionResult Index()
{
var xyz = Service.SampleMethod(new SampleClass());
return View();
}
I can call this service from my unit test project or from a desktop application. But when I call the service from an MVC application it throws ProtocolException:
An exception of type 'System.ServiceModel.ProtocolException' occurred in mscorlib.dll but was not handled in user code
Additional information: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:sampleParameter. The InnerException message was 'Error in line 1 position 451. 'EndElement' 'MyProperty2' from namespace 'http://schemas.datacontract.org/2004/07/DataContracts' is not expected. Expecting element '_increment'.'. Please see InnerException for more details.
I have a hunch that this is caused by some serializer related issue, but I don't really have deep understanding on those topics, so here I am.
What might be the cause of this behaviour? How can I overcome this without changing my data structures?
Update
Btw I realized that the exception occurs on return. When I throw an exception from within the service method, that exception propogates to the client. Therefore I can say my request with ObjectId can be received from the service but cannot return to the client.
We've found out the problem and the solution in the discussion with #jpgrassi, but since #jpgrassi is too humble to post the answer, here I am.
Following the answer of this question #jeff's answer was inspiring enough to make me check the MongoDB.Bson dll's versions. There it was, they were different on server and mvc client and causing this problem. Leveling them on a version solved the problem.

Return Inherited Class into Base Class WCF Service

I am trying to return a derived class from the base class using WCF service, but I keep getting the following exception
"An error occurred while receiving the HTTP response to http://localhost:50137/Service.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server..."
I have tried adding all of the following over WCF Service method.
1) [XmlInclude(typeof(DerivedClass1)), XmlInclude(typeof(DerivedClass2))]
2) [SoapRpcMethod]
3) [SoapInclude(typeof(DerivedClass1)), SoapInclude(typeof(DerivedClass2))]
Code:
public class BaseClass
{
}
public class DerivedClass1:BaseClass
{
}
public class DerivedClass2:BaseClass
{
}
Wcf Service Method:
public BaseClass Validate()
{
if(someCondition)
return new DerivedClass1();
else
return new DerivedClass2();
}
[Serializable]
[DataContract]
[
KnownType(typeof(DerivedClass1)),
KnownType(typeof(DerivedClass2))
]
public class BaseClass
{
}
public class DerivedClass1:BaseClass
{
}
public class DerivedClass2:BaseClass
{
}
see
https://msdn.microsoft.com/en-us/magazine/gg598929.aspx for more information about Known Types and the Generic Resolver.
There are a number of problems with the code you've posted:
Your contract type and operation code have no ServiceModel annotations
You haven't specified how you're hosting the service
You haven't specified how you're calling the service
You haven't specified anything about the binding you're using
Until at least some of these are clarified I think the question is unanswerable. If you could edit your question to include these points I'll edit my answer.

Autofac WCF Integration - Resolve dependencies based on request data

How can I configure an Autofac container so it resolves the dependencies of a WCF service based on properties values of the operation-parameter (request object)?
For example, given this data contract...
[DataContract]
public class MyRequest
{
[DataMember]
public bool MyBool { get; set; }
}
this WCF service...
public class MyWcfService : IWcfService
{
private IService m_service;
public MyWcfService(IService service)
{
m_service = service;
}
public virtual MyResponse Operation(MyRequest request) { }
}
and these dependencies...
public interface IService { }
public class TypeA : IService { }
public class TypeB : IService { }
I would like the container to resolve TypeA if MyBool equals true and TypeB otherwise. Is that feature available? Should I approach the problem differently?
Constraints:
Avoiding the Autofac.Extras.Multitenant package is a plus.
Keeping the signature of the service constructor unchanged is also desired. (See my answer below)
There are a few ways to achieve this. One of the ways is to use IIndex<K,V>. It's built-in "lookup" feature that chooses between service implementations based on a key. You can find more info on Autofac's wiki page. An example code could look like:
// Register your dependency with a key, for example a bool flag
builder.RegisterType<TypeA>().Keyed<IService>(true);
builder.RegisterType<TypeB>().Keyed<IService>(false);
// Your service could look like:
public class MyWcfService
{
private readonly IIndex<bool, IService> _services;
// Inject IIndex<Key,Value> into the constructor, Autofac will handle it automatically
public MyWcfService(IIndex<bool, IService> services)
{
_services = services;
}
public virtual void Operation(MyRequest request)
{
// Get the service that you need by the key
var service = _services[request.MyBool];
}
}
Another approach is to use Metadata feature. More information on wiki page.
Option 1 - Using Autofac:
The Autofac instance provider that creates your service instance does not use or pass along the operation's message. Here's the latest implementation of the method in Autofac. Notice the message parameter is unused.
public class AutofacInstanceProvider : IInstanceProvider
{
// lots of code removed...
public object GetInstance(InstanceContext instanceContext, Message message)
{
if (instanceContext == null)
{
throw new ArgumentNullException("instanceContext");
}
var extension = new AutofacInstanceContext(_rootLifetimeScope);
instanceContext.Extensions.Add(extension);
return extension.Resolve(_serviceData);
}
}
So to get the behavior you want with existing Autofac code, you'll need to inject the dependency into your class using something other than constructor injection, which is #Alexandr Nikitin's solution. This is reasonable, but I agree with the comment "not loving it".
Option 2 - A Custom IInstanceProvider:
Writing a custom WCF IInstanceProvider is a reasonable option, but it will be a lot of code.
The good news is that the code in Autoface.Integration.WCF is a nice example and you could plug your implementation into Autofac.
The bad news is that Autofac.Integration.WCF code doesn't itself use dependency injection. For example AutofacDependencyInjectionServiceBehavior directly calls var instanceProvider = new AutofacInstanceProvider(_rootLifetimeScope, _serviceData). As a result you'll you have to implement a replacement for AutofacInstanceProvider, AutofacDependencyInjectionServiceBehavior, AutofacHostFactory, and probably more. Then you'll need to create an extension for the AutofacInstanceContext to contain the information read from the message. Its a lot of code.
If you are going to do the custom IInstanceProvider I suggest reading up on Carlos Figueira's blog:
WCF Extensibility – IInstanceProvider - for good background
WCF Extensibility – Message Inspectors - Search for the section that starts with WCF Message objects can only be “consumed once". You'll need to follow these rules when inspecting the message.

WCF - Passing objects that are not declared as a ServiceKnownType

I have the following WCF interface that is exposed via net.tcp:
[ServiceContract]
public interface IMyWCFService
{
[OperationContract]
Response ProcessRequest(Request request);
}
This is driven by the following classes (much simplified for the purposes of this question):
[Serializable]
public abstract class Message
{
[XmlAttribute]
public string Sender { get; set; }
[XmlAttribute]
public string Recevier { get; set; }
}
[Serializable]
public abstract class Response : Message
{
[XmlAttribute]
public int EventCode { get; set; }
}
[Serializable]
public abstract class Request : Message
{
[XmlAttribute]
public string SourceSystem { get; set; }
}
[XmlRoot(Namespace="http://blah.blah.com/blah/")]
public class StringRequest : Request
{
[XmlElement]
public string Payload { get; set; }
}
[XmlRoot(Namespace="http://blah.blah.com/blah/")]
public class StringResponse : Response
{
[XmlElement]
public string Payload { get; set; }
}
Note : We use XMLSerializer rather than DataContractSerializer as these classes have to be compatible with legacy systems that are .NET 2 based.
As the interface uses the abstract Request/Response classes in the ProcessRequest method we have to declare StringResponse / StringRequest as ServiceKnownType, for example:
[ServiceContract]
[ServiceKnownType(typeof(StringRequest))]
[ServiceKnownType(typeof(StringResponse))]
public interface IMyWCFService
{
[OperationContract]
ResponseMessage ProcessRequest(RequestMessage request);
}
This works perfectly and all is good in the world, however.....
The WCF listener is just one component of a much larger framework and the classes described above are used throughout. We have also designed the framework to allow us to add new types of Request/Response messages with relative ease. For example I might add:
public class CustomRequest : Request
{
public MyCustomXmlSerialisableRequestObject Payload { get; set; }
}
public class CustomResponse: Response
{
public MyCustomXmlSerialisableResponseObject Payload { get; set; }
}
Which also works fine until I get the the WCF service interface. When we add a new custom request/response pair we also need to update the ServiceKnownType on the interface to include them. Which then means I have to redeploy the service. So the question is - is there any way I can avoid having to update the interface?
As an example when we used remoting we could pass through any objects we liked as long as they were serialisable so I assume/hope that there is a similar solution in WCF.
EDIT : Update
Following the guidance found here:
http://ashgeek.blogspot.com/2011/02/wcf-serialization-dynamically-add.html
I seem to be on the right track. However when I update the client service reference it pulls in all the dynamically types into the service reference. Which is undesirable as not all clients need to, or should, know about all messages that derive from Request/Response
More importantly I seem to lose the the ServiceClient class that is used to push messages, e.g:
// Client proxy class goes AWOL after service reference update
var client = new MyServiceReference.Client();
var responseMessage = client.ProcessRequest(requestMessage)
At the beginning you are mentioning that you need compatibility with .NET 2.0 services but in the same time you are complaining that something which worked in .NET remoting doesn't work in WCF - you are limited by features possible with .NET 2.0 web services where both server and client must know about transferred types on the service layer = types must be in service description and WSDL. Moreover because you decided to use XmlSerializer you generally lost most of the ways how to achieve that:
ServiceKnowType can load known types from static method
KnownTypes defined in configuration (requires DataContractSerializer)
DataContractResolver (only WCF 4) and loading all derived types on startup (requires DataContractSerializer)
Passing .NET type information in messages (requires NetDataContractSerializer and custom behavior) = generally this is the same functionality as in remoting and it demands sharing types between service and client and both service and client must be .NET application using WCF stuff.
With XmlSerializer you have one option
Return XElement and receive XElement in your service operation and deal with XML by yourselves - doesn't work in .NET 2.0
Edit:
There is no dynamic behavior in service description. It is created only once when the host starts and after that doesn't change until you restart the host. If you need subset of WSDL per client you need separate endpoint for each client and you must define exactly which data contracts should be exposed on each endpoint.

WCF OperationContract property forgets value

recently have been successful getting my IIS hosted WCF service to work with basic authentication.
Since successfully implementing that. I have noticed that property values are not remembered.
Here is some code:
[ServiceContract]
public interface IEcho
{
string Message { [OperationContract]get; [OperationContract]set; }
[OperationContract]
string SendEcho();
}
public class EchoProxy : IEcho
{
public string Message { get; set; }
public string SendEcho()
{
return string.Concat("You said: ", Message);
}
}
public class EchoService : System.ServiceModel.ClientBase<IEcho>, IEcho
{
//-- ..... CONSTRUCTORS OMITTED ....
public string Message
{
get { return base.Channel.Message; }
set { base.Channel.Message = value; }
}
public string SendEcho()
{
return base.Channel.SendEcho();
}
}
Here is the console and the result:
EchoService client = new EchoService("SecureEndpoint");
client.ClientCredentials.UserName.UserName = "test";
client.ClientCredentials.UserName.Password = "P#ssword1";
client.Message = "Hello World";
Console.WriteLine(client.SendEcho());
Expected Result: You said: Hello World
Actual Result: You said:
I have Uploaded the sandbox project to my skydrive. I have included a SETUP.txt in the API project.
Click here to download.
How can I get properties to work?
thank you
I have never seen WCF contract used with a property to transfer data. i.e. the Message property. AFAIK its just not possible.
My recommendation would be to keep the concerns that are part of the contract separate, i.e. Operation and Data.
[ServiceContract]
public interface IEcho
{
[OperationContract]
string SendEcho(string Message);
}
Or
[ServiceContract]
public interface IEcho
{
[OperationContract]
string SendEcho(Message message);
}
[DataContract]
public class Message
{
[DataMember]
public string Message {get; set;}
}
At some later point you may wish to change the Message Object.
[DataContract]
public class MessageV2 : Message
{
[DataMember]
public DateTime Sent {get; set;}
}
While this changes the contract, changes like this can be backwardly compatible if managed carefully.
To understand what's happening, you need to know how the lifetime of the service object you're connecting to is configured. A good starting point is the MSDN article on Sessions, Instancing, and Concurrency.
For example, with InstanceContextMode.PerCall, a new service object will be created for each call, so no properties of the service object will be remembered between calls.
At the other end of the scale, InstanceContextMode.Single means a single instance handles all client requests for the lifetime of the application. In this case properties set by one client will be visible to all clients, not usually desirable.
In general, I would recommend using a stateless service object. But if you want a stateful service object (e.g. one with properties), you should use InstanceContextMode.PerSession, and (important) use a binding that supports sessions.
While I agree with #JTew that you shouldn't generally expose operations as properties, you will have the same problem if you try to use an object that stores state between calls in another way (such as a private field). I.e. the following would have exactly the same problem:
[ServiceContract]
public interface IEcho
{
[OperationContract]
void SetMessage(string message);
[OperationContract]
string GetMessage();
... etc ...
}

Categories