I'm trying to hook the event (Action in that case) but cant return from proxy without exception. Here's the idea: I have the interface of events, they not subscribed on client side. So when I try raise event on client side, I catch this event in proxy and send to my remote server the name of this event and his parameters and i wanna just return from proxy. Here my sample
public interface IMyEvents
{
Action OnPing { get; set; }
}
public class Proxy : RealProxy
{
Type type;
public Proxy(Type type)
: base(type)
{
this.type = type;
}
public override IMessage Invoke(IMessage msg)
{
var call = (IMethodCallMessage)msg;
string MethodName = (string)msg.Properties["__MethodName"];
object[] parameters = (object[])msg.Properties["__Args"];
// Send Command to server
// SendData(MethodName, parameters);
// tell the invoker that everything's fine
return new ReturnMessage(null, null, 0, call.LogicalCallContext, call);
}
}
public class Test
{
public Test()
{
Proxy proxy = new Proxy(typeof(IMyEvents));
Events = (IMyEvents)proxy.GetTransparentProxy();
}
public readonly IMyEvents Events;
}
class Program
{
public static void Main(string[] args)
{
Test t = new Test();
t.Events.OnPing(); // NullReferenceException
}
}
Related
I've implemented Command Design Pattern according to below UML
Where Command is is an interface called ICommand:
public interface ICommand
{
CommandType CommandType { get; set; }
Task Execute();
}
It was perfect design until i have been requested to return value from Task Execute(); for specific concrete command, So i thought "OK, lets add a new method Task<T> Execute<T>();" but it means that i need to add empty implementation to all classes that implement ICommand interface (around 10 classes).
I would like that ConcreteCommand will have only one of Execute method, is it possible?
Is it must have empty implementation to other method for every ConcreteCommand ?
Is there a way to combine those method into one using Task?
Just for clarification, I don't want to have two methods like this:
public interface ICommand
{
CommandType CommandType { get; set; }
Task Execute();
Task<T> Execute<T>();
}
Thanks!
Since the Invoker can change Commands at runtime, there must be loose type safety. For cases where you know the command's return value, you can pass its return type to execute():
using System;
class Receiver {
public bool someAction() {
return false;
}
public string someAction2() {
return "some action value";
}
public void voidAction() {
Console.WriteLine("void action");
}
}
interface ICommand {
object doAction();
};
class ConcreteCommand : ICommand {
private Receiver receiver;
public ConcreteCommand(Receiver recv) {
receiver = recv;
}
public object doAction() {
return receiver.someAction();
}
}
class ConcreteCommand2 : ICommand {
private Receiver receiver;
public ConcreteCommand2(Receiver recv) {
receiver = recv;
}
public object doAction() {
return receiver.someAction2();
}
}
class VoidCommand : ICommand {
private Receiver receiver;
public VoidCommand(Receiver recv) {
receiver = recv;
}
public object doAction() {
receiver.voidAction();
return true;
}
}
class Invoker {
private ICommand command;
public void setCommand(ICommand cmd) {
command = cmd;
}
public T execute<T>() {
return (T) command.doAction();
}
}
public class Program
{
public static void Main()
{
Invoker i = new Invoker();
Receiver r = new Receiver();
i.setCommand(new ConcreteCommand(r));
Console.WriteLine(i.execute<bool>());
i.setCommand(new ConcreteCommand2(r));
Console.WriteLine(i.execute<string>());
i.setCommand(new VoidCommand(r));
i.execute<object>();
ICommand[] commands = new ICommand[] {
new ConcreteCommand(r),
new ConcreteCommand(r),
new ConcreteCommand2(r),
new ConcreteCommand2(r),
new VoidCommand(r)
};
foreach (ICommand c in commands) {
i.setCommand(c);
Console.WriteLine(i.execute<object>());
}
}
}
False
some action value
void action
False
False
some action value
some action value
void action
True
There's the following interface which defines a packet.
public interface IPacket
{
int Size { get; }
}
There are two implementations, each with its own additional property.
public class FooPacket : IPacket
{
public int Size => 10;
public string FooProperty { get; set; }
}
public class BarPacket : IPacket
{
public int Size => 20;
public string BarProperty { get; set; }
}
The above is library code I have no control over. I want to create a handler for packets
public interface IPacketHandler<T> where T : IPacket
{
void HandlePacket(T packet) ;
}
and create two implementations for the concrete packets.
public class FooPacketHandler : IPacketHandler<FooPacket>
{
public void HandlePacket(FooPacket packet) { /* some logic that accesses FooProperty */ }
}
public class BarPacketHandler : IPacketHandler<BarPacket>
{
public void HandlePacket(BarPacket packet) { /* some logic that accesses BarProperty */ }
}
I'd like to inject a list of packet handlers into a class that manages packet handling so that it can be extended in the future with additional packet handlers.
public class PacketHandlerManager
{
public PacketHandlerManager(IEnumerable<IPacketHandler<IPacket>> packetHandlers)
{
}
}
The trouble I'm having is when creating the injected parameter. I cannot do
var packetHandlers = new List<IPacketHandler<IPacket>>
{
new FooPacketHandler(),
new BarPacketHandler()
};
because I cannot create an instance like so:
IPacketHandler<IPacket> packetHandler = new FooPacketHandler();
I get the error Cannot implicitly convert type 'FooPacketHandler' to 'IPacketHandler<IPacket>. An explicit conversion exists (are you missing a cast?)
I had a look at a similar question: Casting generic type with interface constraint. In that question, OP didn't show the members of the interface, only the definition of it from a generics point of view. From what I can see, if my interface didn't use the generic type parameter as an input, I could make it covariant using the out keyword, but that doesn't apply here.
How do I achieve making manager adhere to the open-closed principle? Is my only recourse changing the interface definition to
public interface IPacketHandler
{
void HandlePacket(IPacket packet);
}
and then casting to a particular packet in the implementation?
The core of the issue is that ultimately you would call your handler passing a concrete packet (of a concrete type) to it as an argument, even though you hide the argument behind IPacket.
Somehow then, trying to call the HandlePacket( FooPacket ) with BarPacket argument would have to fail, the only question is when/where it fails.
As you already noticed, introducing the generic parameter to the packet handler makes it fail in the compile time and there is no easy workaround over it.
Your idea to drop the generic parameter, i.e. to have
public interface IPacketHandler
{
void HandlePacket(IPacket packet);
}
is a possible solution. It however pushes the possible failure to the runtime, where you now have to check if a handler is called with inappropriate argument.
What you could also do is to make this runtime check more explicit by introducing a contract for it:
public interface IPacketHandler
{
bool CanHandlePacket(IPacket packet);
void HandlePacket(IPacket packet);
}
This makes it cleaner for the consumer to safely call HandlePacket - assuming they get a positive result from calling CanHandlePacket before.
For example, a possible naive loop over a list of packets and calling your handlers would become
foreach ( var packet in _packets )
foreach ( var handler in _handlers )
if ( handler.CanHandlePacket(packet) )
handler.HandlePacket(packet);
You can solve this with a little bit of reflection.
Firstly, for convenience (and to help slightly with type-safety), introduce a "Tag" interface which all your IPacketHandler<T> interfaces will implement:
public interface IPacketHandlerTag // "Tag" interface.
{
}
This is not really necessary, but it means you can use IEnumerable<IPacketHandlerTag> instead of IEnumerable<object> later on, which does make things a little more obvious.
Then your IPacketHandler<T> interface becomes:
public interface IPacketHandler<in T> : IPacketHandlerTag where T : IPacket
{
void HandlePacket(T packet);
}
Now you can write a PacketHandlerManager that uses reflection to pick out the method to use to handle a packet, and add it to a dictionary like so:
public class PacketHandlerManager
{
public PacketHandlerManager(IEnumerable<IPacketHandlerTag> packetHandlers)
{
foreach (var packetHandler in packetHandlers)
{
bool appropriateMethodFound = false;
var handlerType = packetHandler.GetType();
var allMethods = handlerType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
foreach (var method in allMethods.Where(m => m.Name == "HandlePacket"))
{
var args = method.GetParameters();
if (args.Length == 1 && typeof(IPacket).IsAssignableFrom(args[0].ParameterType))
{
_handlers.Add(args[0].ParameterType, item => method.Invoke(packetHandler, new object[]{item}));
appropriateMethodFound = true;
}
}
if (!appropriateMethodFound)
throw new InvalidOperationException("No appropriate HandlePacket() method found for type " + handlerType.FullName);
}
}
public void HandlePacket(IPacket packet)
{
if (_handlers.TryGetValue(packet.GetType(), out var handler))
{
handler(packet);
}
else
{
Console.WriteLine("No handler found for packet type " + packet.GetType().FullName);
}
}
readonly Dictionary<Type, Action<IPacket>> _handlers = new Dictionary<Type, Action<IPacket>>();
}
If a packet handler passed to the PacketHandlerManager constructor does not implement a method called HandlePacket with a single argument that is assignable from IPacket, it will throw an InvalidOperationException.
For example, attempting to use an instance of the following class would cause the constructor to throw:
public class BadPacketHandler: IPacketHandlerTag
{
public void HandlePacket(string packet)
{
Console.WriteLine("Handling string");
}
}
Now you can call use it thusly:
var packetHandlers = new List<IPacketHandlerTag>
{
new FooPacketHandler(),
new BarPacketHandler()
};
var manager = new PacketHandlerManager(packetHandlers);
var foo = new FooPacket();
var bar = new BarPacket();
var baz = new BazPacket();
manager.HandlePacket(foo);
manager.HandlePacket(bar);
manager.HandlePacket(baz);
Putting it all together into a compilable console app:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ConsoleApp1
{
public interface IPacket
{
int Size { get; }
}
public class FooPacket : IPacket
{
public int Size => 10;
public string FooProperty { get; set; }
}
public class BarPacket : IPacket
{
public int Size => 20;
public string BarProperty { get; set; }
}
public class BazPacket : IPacket
{
public int Size => 20;
public string BazProperty { get; set; }
}
public interface IPacketHandlerTag // "Tag" interface.
{
}
public interface IPacketHandler<in T> : IPacketHandlerTag where T : IPacket
{
void HandlePacket(T packet);
}
public class FooPacketHandler : IPacketHandler<FooPacket>
{
public void HandlePacket(FooPacket packet)
{
Console.WriteLine("Handling FooPacket");
}
}
public class BarPacketHandler : IPacketHandler<BarPacket>
{
public void HandlePacket(BarPacket packet)
{
Console.WriteLine("Handling BarPacket");
}
}
public class PacketHandlerManager
{
public PacketHandlerManager(IEnumerable<IPacketHandlerTag> packetHandlers)
{
foreach (var packetHandler in packetHandlers)
{
bool appropriateMethodFound = false;
var handlerType = packetHandler.GetType();
var allMethods = handlerType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
foreach (var method in allMethods.Where(m => m.Name == "HandlePacket"))
{
var args = method.GetParameters();
if (args.Length == 1 && typeof(IPacket).IsAssignableFrom(args[0].ParameterType))
{
_handlers.Add(args[0].ParameterType, item => method.Invoke(packetHandler, new object[]{item}));
appropriateMethodFound = true;
}
}
if (!appropriateMethodFound)
throw new InvalidOperationException("No appropriate HandlePacket() method found for type " + handlerType.FullName);
}
}
public void HandlePacket(IPacket packet)
{
if (_handlers.TryGetValue(packet.GetType(), out var handler))
{
handler(packet);
}
else
{
Console.WriteLine("No handler found for packet type " + packet.GetType().FullName);
}
}
readonly Dictionary<Type, Action<IPacket>> _handlers = new Dictionary<Type, Action<IPacket>>();
}
class Program
{
public static void Main()
{
var packetHandlers = new List<IPacketHandlerTag>
{
new FooPacketHandler(),
new BarPacketHandler()
};
var manager = new PacketHandlerManager(packetHandlers);
var foo = new FooPacket();
var bar = new BarPacket();
var baz = new BazPacket();
manager.HandlePacket(foo);
manager.HandlePacket(bar);
manager.HandlePacket(baz);
}
}
}
The output of this is:
Handling FooPacket
Handling BarPacket
No handler found for packet type ConsoleApp1.BazPacket
Thanks for the answers. The solution I ended up with is this, starting with the library code:
public enum PacketType
{
Foo,
Bar
}
public interface IPacket
{
PacketType Type { get; }
}
public class FooPacket : IPacket
{
public PacketType Type => PacketType.Foo;
public string FooProperty { get; }
}
public class BarPacket : IPacket
{
public PacketType Type => PacketType.Bar;
public string BarProperty { get; }
}
The above version is a better approximation of the real thing.
public interface IPacketHandler
{
void HandlePacket(IPacket packet);
}
public abstract class PacketHandler<T> : IPacketHandler where T : IPacket
{
public abstract PacketType HandlesPacketType { get; }
public void HandlePacket(IPacket packet)
{
if (packet is T concretePacket)
{
HandlePacket(concretePacket);
}
}
protected abstract void HandlePacket(T packet);
}
public class FooPacketHandler : PacketHandler<FooPacket>
{
public override PacketType HandlesPacketType => PacketType.Foo;
protected override void HandlePacket(FooPacket packet) { /* some logic that accesses FooProperty */ }
}
public class BarPacketHandler : PacketHandler<BarPacket>
{
public override PacketType HandlesPacketType => PacketType.Bar;
protected override void HandlePacket(BarPacket packet) { /* some logic that accesses BarProperty */ }
}
public class PacketHandlerManager
{
public PacketHandlerManager(Library library, IEnumerable<IPacketHandler> packetHandlers)
{
foreach (var packetHandler in packetHandlers)
{
library.Bind(packetHandler.HandlesPacketType, packetHandler.HandlePacket);
}
}
}
There's some more logic in PacketHandlerManager which I've omitted here. library dispatches packets to handlers, so I don't have to deal with that explicitly after I register handlers using the Bind method.
It's not exactly what I imagined, but it'll do.
I'm using WCF and I made my own proxy in the client, and i want to create a method using lambda expression or Action that will excute everything.
Here is my proxy:
public class BooksProxy
{
public ChannelFactory<IBooksService> Channel { get; set; }
public BooksProxy()
{
Channel = new ChannelFactory<IBooksService>("endpoint");
}
public IBooksService CreateChannel()
{
return Channel.CreateChannel();
}
}
Here is how i use the proxy:
IBooksService proxy = BooksProxy.CreateChannel();
IList<string> lst = proxy.GetStrings();
((ICommunicationObject)proxy).Close();
I want to do something like this in the BooksProxy class:
public void Execute(Action<...> action)
{
IBooksService proxy = this.CreateChannel();
/* executing here. */
((ICummunicationObject)proxy).Close();
}
And to call it like this maybe:
IList<string> result = null;
BooksProxy.Execute(proxy => { result = proxy.GetStrings(); });
Not quite sure how to do that...
Ok, so I figured how to do it.
Here is the Proxy, The idea is to make it generic:
public class Proxy<T>
{
public ChannelFactory<T> Channel { get; set; }
public Proxy()
{
Channel = new ChannelFactory<T>("endpoint");
}
public T CreateChannel()
{
return Channel.CreateChannel();
}
}
Now here is the trick :
For void methods :
public void Execute(Action<T> action)
{
T proxy = CreateChannel();
action(proxy);
((ICommunicationObject)proxy).Close();
}
For return:
public TResult Execute<TResult>(Func<T, TResult> function)
{
T proxy = CreateChannel();
var result = function(proxy);
((ICommunicationObject)proxy).Close();
return result;
}
Where the TResult is the returning type.
How to use:
Proxy<IService> proxy = new Proxy();
// for a void method
Proxy.Execute(prxy => prxy.Method());
// for non void method.
var result = Proxy.Execute(prxy => prxy.Method());
So, to sum up, here is how the proxy class should look like:
public class Proxy<T>
{
public ChannelFactory<T> Channel { get; set; }
public Proxy()
{
Channel = new ChannelFactory<T>("endpoint");
}
public T CreateChannel()
{
return Channel.CreateChannel();
}
public void Execute(Action<T> action)
{
T proxy = CreateChannel();
action(proxy);
((ICommunicationObject)proxy).Close();
}
public TResult Execute<TResult>(Func<T, TResult> function)
{
T proxy = CreateChannel();
var result = function(proxy);
((ICommunicationObject)proxy).Close();
return result;
}
}
I recommend this solution for a custom wcf proxy without using any service reference, its really simple and easy.
I want to be able to catch all unhandled exceptions and return the expected DTO but with some error information filled in. For example
public class CreateFooRequest
{
public string Name { get; set; }
}
public class CreateFooResponse
{
public Foo Created { get; set; }
public string Error { get; set; } // If call was successful then this will be null
public string Detail { get; set; }
}
public interface IFooService
{
CreateFooResponse Create(CreateFooRequest request);
}
public ErrorHandler: IErrorHandler
{
public bool Handle(Exception ex)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// Some how figure out that IFooService.Create was called.
// Inspect the method signature and see that there is an input called CreateFooRequest
// Use reflection to initialize response objects that will replace the "Request" with "Response"
var response = new CreateFooResponse();
response.Error = error.GetType().Name;
// I think i need one of the following overloads
fault = Message.CreateMessage(version, action, response);
}
}
Is doing something like this even possible? We are using NetTCP as our binding if that makes a difference.
IErrorHandler is designed to generate fault contracts. If you don't want to return a fault, you are better off taking an interceptor approach and using a the IOperationInvoker extension point instead.
The operation invoker is the part of the WCF framework that actually calls the service method. When you extend it, you can effectively "intercept" the call to the service. Note the Invoker does have responsibilities. You can't simply replace the WCF invoker implementation. Instead you chain them (see below).
At a high level the steps are:
Create an IOperationInvoker.Invoke() that implements a try/catch block. Catch the exceptions you want to be Response messages instead of FaultExceptions.
Create an IOperationBehavior (that's optionally also an attribute) to apply the behavior to your service.
The approach has a couple of advantages:
The exception is caught before WCF sees it.
In a IOperationBehavior.ApplyDispatchBehavior() you have access to the OperationDescription at the time of service start up. If you save this in the Invoker, you don't need to use reflection to capture the method's return type.
The IOperationBehavior.Validate() allows robust checks to ensure that the return type can actually be processed.
Below is a complete windows console application that demonstrates the approach. Paste it into Visual Studio, add the obvious assembly references, and run it.
My apologizes for the large amount of code and excessive use of base classes. I'm cutting down from actual production code.
If you want a better understanding of the IOperationInvoker extension point and what the example InvokerBase class is doing see Carlos Figueira's blog.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Threading.Tasks;
namespace WcfErrorResponse
{
/// <summary>
/// Provides a base IOperationInvoker implementation that stores and passes through calls to the exisiting (old) invoker
/// </summary>
public abstract class InvokerBase : IOperationInvoker
{
private readonly IOperationInvoker m_OldInvoker;
protected IOperationInvoker OldInvoker
{
get { return m_OldInvoker; }
}
public InvokerBase(IOperationInvoker oldInvoker)
{
m_OldInvoker = oldInvoker;
}
public virtual object[] AllocateInputs()
{
return OldInvoker.AllocateInputs();
}
public virtual object Invoke(object instance, object[] inputs, out object[] outputs)
{
return OldInvoker.Invoke(instance, inputs, out outputs);
}
public virtual IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return OldInvoker.InvokeBegin(instance, inputs, callback, state);
}
public virtual object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return OldInvoker.InvokeEnd(instance, out outputs, result);
}
public virtual bool IsSynchronous
{
get { return OldInvoker.IsSynchronous; }
}
}
/// <summary>
/// Base implementation for a Method level attribte that applies a <see cref="InvokerBase"/> inherited behavior.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public abstract class InvokerOperationBehaviorAttribute : Attribute, IOperationBehavior
{
protected abstract InvokerBase CreateInvoker(IOperationInvoker oldInvoker, OperationDescription operationDescription, DispatchOperation dispatchOperation);
public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{ }
public virtual void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
// chain invokers.
IOperationInvoker oldInvoker = dispatchOperation.Invoker;
dispatchOperation.Invoker = CreateInvoker(oldInvoker, operationDescription, dispatchOperation);
}
public virtual void Validate(OperationDescription operationDescription)
{
return;
}
}
public class ResponseExceptionInvoker : InvokerBase
{
private Type returnType;
public ResponseExceptionInvoker(IOperationInvoker oldInvoker, OperationDescription operationDescription)
: base(oldInvoker)
{
// save the return type for creating response messages
this.returnType = operationDescription.GetReturnType();
if (this.returnType == null)
{
throw new InvalidOperationException("The operation '" + operationDescription.SyncMethod.DeclaringType.Name + "' does not define a return type.");
}
}
public override object Invoke(object instance, object[] inputs, out object[] outputs)
{
object returnedValue = null;
object[] outputParams = new object[] { };
outputs = new object[] { };
try
{
returnedValue = OldInvoker.Invoke(instance, inputs, out outputParams);
outputs = outputParams;
return returnedValue;
}
catch (Exception ex)
{
Logger.Debug("ResponseExceptionInvoker() - Caught Exception. A Response Message will be returned. Message='" + ex.Message + "'");
// there was an excpetion. Do not assign output params... their state is undefined.
//outputs = outputParams;
try
{
// assumes the behavior only used for return types that inherit from Response, as verified by ResponseExceptionOperationBehaviorAttribute.Validate()
Response response = (Response)Activator.CreateInstance(this.returnType);
response.Success = false;
response.ErrorMessage = ex.Message;
return response;
}
catch (Exception exCreateResponse)
{
// Log that the Response couldn't be created and throw the original exception.
// Probably preferable to wrap and throw.
Logger.Error("Caught ResponseException, but unable to create the Response object. Likely indicates a bug or misconfiguration. Exception will be rethrown." + exCreateResponse.Message);
}
throw;
}
}
}
public class ResponseExceptionOperationBehaviorAttribute : InvokerOperationBehaviorAttribute
{
protected override InvokerBase CreateInvoker(IOperationInvoker oldInvoker, OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
return new ResponseExceptionInvoker(oldInvoker, operationDescription);
}
public override void Validate(OperationDescription operationDescription)
{
// validate that this attribute can be applied to the service behavior.
Type returnType = operationDescription.GetReturnType();
if (!typeof(Response).IsAssignableFrom(returnType))
{
throw new InvalidOperationException("'" + returnType.FullName + "' does not inherit from '" + typeof(Response).FullName +
"'. ImplicitResponse behavior applied to '" + operationDescription.SyncMethod.DeclaringType.Name + "." + operationDescription.Name +
"' requires the method return type inherit from '" + typeof(Response).FullName);
}
}
}
static class OperationDescriptionExtensions
{
public static Type GetReturnType(this OperationDescription operationDescription)
{
if (operationDescription.SyncMethod == null)
throw new InvalidOperationException("These behaviors have only been tested with Sychronous methods.");
// !! Warning: This does NOT work for Asynch or Task based implementations.
System.Reflection.MethodInfo method = operationDescription.SyncMethod ?? operationDescription.EndMethod;
return method.ReturnType;
}
}
// When not using FaultContracts, return success/fail as a part of all responses via some base class properties.
[DataContract]
public class Response
{
[DataMember]
public bool Success { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
}
public class ChildResponse : Response
{
[DataMember]
public string Foo { get; set; }
}
[DataContract]
public class Request
{
[DataMember]
public string Name { get; set; }
}
[ServiceContract]
public interface ISimple
{
[OperationContract]
ChildResponse Work(Request request);
[OperationContract]
ChildResponse Fail(Request request);
}
public class SimpleService : ISimple
{
public ChildResponse Work(Request request) {
return new ChildResponse() { Success = true };
}
[ResponseExceptionOperationBehavior]
public ChildResponse Fail(Request request)
{
throw new NotImplementedException("This method isn't done");
}
}
class Program
{
static void Main(string[] args)
{
ServiceHost simpleHost = new ServiceHost(typeof(SimpleService), new Uri("http://localhost/Simple"));
simpleHost.Open();
ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(simpleHost.Description.Endpoints[0]);
ISimple proxy = factory.CreateChannel();
Logger.Debug("Calling Work...");
var response1 = proxy.Work(new Request() { Name = "Foo" });
Logger.Debug("Work() returned Success=" + response1.Success + " message='" + response1.ErrorMessage + "'");
Logger.Debug("Calling Fail...");
var response2 = proxy.Fail(new Request() { Name = "FooBar" });
Logger.Debug("Fail() returned Success=" + response2.Success + " message='" + response2.ErrorMessage + "'");
Console.WriteLine("Press ENTER to close the host.");
Console.ReadLine();
((ICommunicationObject)proxy).Shutdown();
simpleHost.Shutdown();
}
}
public static class CommunicationObjectExtensions
{
static public void Shutdown(this ICommunicationObject obj)
{
try
{
obj.Close();
}
catch (Exception ex)
{
Console.WriteLine("Shutdown exception: {0}", ex.Message);
obj.Abort();
}
}
}
public static class Logger
{
public static void Debug(string message) { Console.WriteLine(message); }
public static void Error(string message) { Console.WriteLine(message); }
}
}
In your place, I would implement this as simple as possible by using general try/catch block. Using custom exception handler to observe the invoked service method and create a corresponding response using reflection looks like an overkill for me.
Make your life easier:
public CreateFooResponse Create(CreateFooRequest request)
{
try
{
// Create Foo
var foo = CreateFoo();
// Return successful CreateFooResponse
return new CreateFooResponse
{
Created = foo,
Error = null,
Detail = "Created successfully"
};
}
catch (Exception ex)
{
// Return CreateFooResponse with an error
return new CreateFooResponse
{
Created = null,
Error = CreateError(ex),
Detail = "Unable to create Foo."
};
}
}
A good example of using custom WCF error handler is to log the error, convert it to the FaultContract and return to the caller. You have a different scenario and I would suggest a different approach.
First of all, I would like to say that it is much better to use faultcontracts. Below I will give an example for service GetDataUsingDataContract:
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
[DataContract]
public class CompositeType
{
[DataMember]
public bool BoolValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
Then, you create a bodyWriter equivalent to a normal response:
public class MyBodyWriter : BodyWriter
{
public CompositeType CompositeType { get; private set; }
public MyBodyWriter(CompositeType composite)
: base(false)
{
CompositeType = composite;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("GetDataUsingDataContractResponse", "http://tempuri.org/");
writer.WriteStartElement("GetDataUsingDataContractResult");
writer.WriteAttributeString("xmlns", "a", null, "http://schemas.datacontract.org/2004/07/WcfService1");
writer.WriteAttributeString("xmlns", "i", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteStartElement("a:BoolValue");
writer.WriteString(CompositeType.BoolValue.ToString().ToLower());
writer.WriteEndElement();
writer.WriteStartElement("a:StringValue");
writer.WriteString(CompositeType.StringValue);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
And finally, you use it in your IErrorHandler:
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// TODO: parse error and gets response
var response = new CompositeType {BoolValue = true, StringValue = "a"};
fault = Message.CreateMessage(version, "http://tempuri.org/", new MyBodyWriter(response));
}
I did a test and I can get a correct answer if the service throws an exception or if the service responds normally:
var response1 = client.GetDataUsingDataContract(null);
var response2 = client.GetDataUsingDataContract(new CompositeType { StringValue = "a", BoolValue = true });
I'm trying to make my client subscribe to events that happen on my server.
I have an interface that looks like this:
public delegate void RemoteEventHandler(object sender, ClientEventArgs args);
[Serializable]
public class ClientEventArgs : EventArgs
{
public ClientEventArgs()
{ }
public ClientEventArgs(Client _client)
{
MyClient = _client;
}
public Client MyClient { get; set; }
}
public interface IMonitor
{
event RemoteEventHandler RemoteEvent;
}
My Server Class looks like this:
public class ConnectionManager : MarshalByRefObject, IMonitor
{
public event RemoteEventHandler RemoteEvent;
// call the below code when th event should fire.
if (RemoteEvent != null)
RemoteEvent(this, new ClientEventArgs(e.MyClient));
}
Then To set my channels up on the server I do this:
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 5001;
TcpChannel channel = new TcpChannel(props, null, provider);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(ConnectionManager),
ConnectionManager",
WellKnownObjectMode.Singleton);
And On the client to set the channels up and subscribe to the event:
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, false);
_monitorObject = (IMonitor)Activator.GetObject(
typeof(IMonitor),
"tcp://localhost:5001/ConnectionManager");
_monitorObject.RemoteEvent += _monitorObject_RemoteEvent;
Can anyone explain where this is going wrong please?
Exception:
System.MissingMethodException was unhandled HResult=-2146233069 Message=No parameterless constructor defined for this object.
Source=mscorlib
To answer your last question: when using Serializable you need a constructor without parameters. So this one would definitely fail:
[Serializable]
public class ClientEventArgs : EventArgs
{
public ClientEventArgs(Client _client)
{
MyClient = _client;
}
public Client MyClient { get; set; }
}
You need to add a parameterless constructor:
[Serializable]
public class ClientEventArgs : EventArgs
{
public ClientEventArgs()
{ }
public ClientEventArgs(Client _client)
{
MyClient = _client;
}
public Client MyClient { get; set; }
}
My money is on your ConnectionManager class not having a default / parameterless constructor. The remoting infrastructure needs to be able to create an instance of it on the server end.