Say you have an object that has a kind of connection to a platform or whatever. For example, an object that is used to connect to a distant web site where you can control various robots.
The producer object is used to get a dozens of instances through the connection representing these robots. These objects are dependent on the first object in that any operations are required to go through the connection. So any local code would just be putting calls through the producer object.
robots <-> connection <-> robotObjects
The originating object could have a certain number of utility methods for each of these instances that would relay changes back. However, that could turn it into a "god" class of some kind which does everything.
How would you go about separating responsibilities in a case like this ?
P.S: Feel free to suggest a better title.
What you describe sounds very similar to the proxy pattern:
There is a Robot interface.
The server controls the real robots through a concrete implementation, say RealRobot.
The client has a Connection object which can return proxies that implement the Robot interface but forward calls through the connection to the real robots.
The Connection object itself would provide only basic communication methods (for eg. to send and receive data) and not contain any of the "utility methods" that you describe. The proxy implementation would make use of these communication methods to relay calls to the server.
Here's an example:
Shared interface:
public interface Robot {
void move(...);
}
Server implementation:
public class RealRobot implements Robot { ... }
Client library:
public class Connection {
public Robot getRobot(int id) {
return new RobotProxy(id, this);
}
// ...
// methods for sending and receiving data
// ...
}
public class RobotProxy implements Robot {
private final int id;
private final Connection conn;
public RobotProxy(int id, Connection conn) {
this.id = id;
this.conn = conn;
}
public void move(...) {
conn.send("move", id, ...);
}
}
Related
I'm writing a WCF service and am using the AutoFac WCF integration for DI. I have a slightly weird situation where I have a proxy to another service that requires credentials. The credentials will change based on some parameters coming in so I can't just set the values when I'm setting up the container and be done with it.
public class MyService : IMyService
{
private ISomeOtherService _client;
public MyService(ISomeOtherService client)
{
_client = client;
}
public Response SomeCall(SomeData data)
{
// how do I set ClientCredentials here, without necessarily casting to concrete implementation
_client.MakeACall();
}
}
What's the best way to set the credentials on proxy without having to cast to a known type or ChannelBase. I'm trying to avoid this because in my unit tests I'm mocking out that proxy interface so casting it back to one of those types would fail.
Any thoughts?
You can do it, but it's not straightforward, and you have to slightly change the design so the logic of "decide and set the credentials" is pulled out of the MyService class.
First, let's define the rest of the classes in the scenario so you can see it all come together.
We have the ISomeOtherService interface, which I've modified slightly just so you can actually see what credentials are getting set at the end. I have it return a string instead of being a void. I've also got an implementation of SomeOtherService that has a credential get/set (which is your ClientCredentials in WCF). That all looks like this:
public interface ISomeOtherService
{
string MakeACall();
}
public class SomeOtherService : ISomeOtherService
{
// The "Credentials" here is a stand-in for WCF "ClientCredentials."
public string Credentials { get; set; }
// This just returns the credentials used so we can validate things
// are wired up. You don't actually have to do that in "real life."
public string MakeACall()
{
return this.Credentials;
}
}
Notice the Credentials property is not exposed by the interface so you can see how this will work without casting the interface to the concrete type.
Next we have the IMyService interface and associated request/response objects for the SomeCall operation you show in your question. (In the question you have SomeData but it's the same idea, I just went with a slightly different naming convention to help me keep straight what was input vs. what was output.)
public class SomeCallRequest
{
// The Number value is what we'll use to determine
// the set of client credentials.
public int Number { get; set; }
}
public class SomeCallResponse
{
// The response will include the credentials used, passed up
// from the call to ISomeOtherService.
public string CredentialsUsed { get; set; }
}
public interface IMyService
{
SomeCallResponse SomeCall(SomeCallRequest request);
}
The interesting part there is that the data we're using to choose the set of credentials is the Number in the request. It could be whatever you want it to be, but using a number here makes the code a little simpler.
Here's where it starts getting more complex. First you really need to be familiar with two Autofac things:
Implicit relationships - we can take a reference on a Func<T> instead of a T to get a "factory that creates T instances."
Using parameters from registration delegates - we can take some inputs and use that to inform the outputs of the resolve operation.
We'll make use of both of those concepts here.
The implementation of MyService gets switched to take a factory that will take in an int and return an instance of ISomeOtherService. When you want to get a reference to the other service, you execute the function and pass in the number that will determine the client credentials.
public class MyService : IMyService
{
private Func<int, ISomeOtherService> _clientFactory;
public MyService(Func<int, ISomeOtherService> clientFactory)
{
this._clientFactory = clientFactory;
}
public SomeCallResponse SomeCall(SomeCallRequest request)
{
var client = this._clientFactory(request.Number);
var response = client.MakeACall();
return new SomeCallResponse { CredentialsUsed = response };
}
}
The real key there is that Func<int, ISomeOtherService> dependency. We'll register ISomeOtherService and Autofac will automatically create a factory that takes in an int and returns an ISomeOtherService for us. No real special work required... though the registration is a little complex.
The last piece is to register a lambda for your ISomeOtherService instead of a simpler type/interface mapping. The lambda will look for a typed int parameter and we'll use that to determine/set the client credentials.
var builder = new ContainerBuilder();
builder.Register((c, p) =>
{
// In WCF, this is more likely going to be a call
// to ChannelFactory<T>.CreateChannel(), but for ease
// here we'll just new this up:
var service = new SomeOtherService();
// The magic: Get the incoming int parameter - this
// is what the Func<int, ISomeOtherService> will pass
// in when called.
var data = p.TypedAs<int>();
// Our simple "credentials" will just tell us whether
// we passed in an even or odd number. Yours could be
// way more complex, looking something up from config,
// resolving some sort of "credential factory" from the
// current context (the "c" parameter in this lambda),
// or anything else you want.
if(data % 2 == 0)
{
service.Credentials = "Even";
}
else
{
service.Credentials = "Odd";
}
return service;
})
.As<ISomeOtherService>();
// And the registration of the consuming service here.
builder.RegisterType<MyService>().As<IMyService>();
var container = builder.Build();
OK, now that you have the registration taking in an integer and returning the service instance, you can just use it:
using(var scope = container.BeginLifetimeScope())
{
var myService = scope.Resolve<IMyService>();
var request = new SomeCallRequest { Number = 2 };
var response = myService.SomeCall(request);
// This will write "Credentials = Even" at the console
// because we passed in an even number and the registration
// lambda executed to properly set the credentials.
Console.WriteLine("Credentials = {0}", response.CredentialsUsed);
}
Boom! The credentials got set without having to cast to the base class.
Design changes:
The credential "set" operation got moved out of the consuming code. If you don't want to cast to the base class in your consuming code, you won't have a choice but to also pull the credential "set" operation out. That logic could be right in the lambda; or you could put it in a separate class that gets used inside that lambda; or you could handle the OnActivated event and do a little magic there (I didn't show that - exercise left to the reader). But the "tie it all together" bit has to be somewhere in the component registration (the lambda, the event handler, etc.) because that's the only point at which you still have the concrete type.
The credentials are set for the lifetime of the proxy. It's probably not good if you have a single proxy in your consuming code where you set different credentials just before you execute each operation. I can't tell from your question if that's how you have it, but... if that's the case, you will need a different proxy for each call. That may mean you actually want to dispose of the proxy after you're done with it, so you'll need to look at using Owned<T> (which will make the factory Func<int, Owned<T>>) or you could run into a memory leak if services are long-lived like singletons.
There are probably other ways to do this, too. You could create your own custom factory; you could handle the OnActivated event that I mentioned; you could use the Autofac.Extras.DynamicProxy2 library to create a dynamic proxy that intercepts calls to your WCF service and sets the credentials before allowing the call to proceed... I could probably brainstorm other ways, but you get the idea. What I posted here is how I'd do it, and hopefully it will at least point you in a direction to help you get where you need to go.
The approach we ended up taking is to cast ISomeOtherService to ClientBase,
This avoids referencing the proxy type. Then in our unit tests we can set up the mock like so
var client = new Mock<ClientBase<ISomeOtherService>>().As<ISomeOtherService>();
So it can be casted to ClientBase, but still setup as ISomeOtherService
I have a WCF service that will be called from a various clients.
Internally the WCF service uses an ISomething. There are multiple implementations of this interface and I need some clients to use one implementation and other clients to use a different implementation.
In addition, I am using Unity and an IoC container. I would typically set up a custom factory to allow the wcf service itself to be resolved along with its dependency graph, but if I have multiple implementations of a dependency, I do not think I can go with this approach and would have to resort to resolving the ISomething within the service (effectively using Unity as a service locator) which is not ideal.
So I need to work out
(1) how to specify which implementation of ISomething a client needs (eg. use a header, pass implementation string in each method, host multiple endpoints etc.)
(2) how Unity fits in?
One option is to write a Decorator that performs the selection for you:
public class RoutingSomething : ISomething
{
private readonly ISomeContext ctx;
private readonly ISomething s1;
private readonly ISomething s2;
private readonly ISomething s3;
public RoutingSomething(ISomeContext ctx)
{
this.ctx = ctx;
// An even better design would be to inject these too
this.s1 = new BarSomething();
this.s2 = new BazSomething();
this.s3 = new QuxSomething();
}
// Assuming ISomething has a Foo method:
public void Foo()
{
if(this.ctx.Bar())
{
this.s1.Foo();
return;
}
if(this.ctx.Baz())
{
this.s2.Foo();
return;
}
if(this.ctx.Qux())
{
this.s3.Foo();
return;
}
}
}
You could generalize this so that ISomeContext is simply an Abstract Factory of ISomething. This then begins to turn into the general solution to varying dependencies based on run-time context.
You can now register RoutingSomething in Unity in addition to your other components. When the container resolves the service, it'll inject an instance of RoutingSomething into it.
I have a WCF application , with multiple WSDL webservices, hosted in IIS7 on Windows Server 2008 64Bit.
The application requires a singleton to be assigned with some configuration values once, when the first webservice method is invoked (no matter what is invoked first).
Edit: The backend of the system requires the use of this singleton approach.
I get the configuration assigned once, but the values become null again....
Here is the code (simplified):
public class SingletonSettings
{
private static readonly SingletonSettings _s;
public SingletonSettings Instance { get {return _s;} }
public object SomeValue { get; set; }
}
public abstract class AbstractWebservice
{
static AbstractWebservice()
{
WebserviceGlobalInitializer.Initialize();
}
}
//Just a webservice
public class Webservice1 : AbstractWebservice, ISomeServiceConctract1
{
public void DoStuff1();
}
//Just a webservice
public class Webservice2 : AbstractWebservice, ISomeServiceConctract2
{
public void DoStuff2();
}
internal class WebserviceGlobalInitializer
{
private static readonly object Lock = new object();
private static bool Initialized = false;
public static void Initialize()
{
lock (Lock)
{
if (!Initialized)
{
InitStuff();
Initialized = true;
}
}
}
private static void InitStuff()
{
string s = SingletonSettings.Instance.SomeValue = "just a ref";
}
}
WebserviceGlobalInitializer.InitStuff() gets invoked only once. Still SingletonSettings.SomeValue becomes null.....
The issue occurs randomly.
I have tried
1) Invoking WebserviceGlobalInitializer.Initialize() from a normal constructor in the base class.
2) Commenting out: Initialized = true; in hope that the settings would then be initialized every time (causing massive overhead, so it would not be a long term solution anyway)
Still the value becomes null.
Any ideas?
With process recycling, all state that is not in session state or application state will disappear into the black hole. This, eye-openingly, includes the static variables, one of which is the singleton instance.
My gut feeling is that the InstanceContextMode of singleton has been implemented as a variable in the ASP.NET Application state. To check this, I will be doing some reflectoring today and will update my answer.
UPDATE
NO IT DOESN'T!!! With process recycling, even if you set the WCF Instancing mode to Single, you lose all state you had with your singleton instance (e.g. counter, whatever) with process recycling.
After a few more days of searching i found the source of the problem. Aliostad's answer gave me a hint.
My webservice uses behavior configurations. One with authentication and one without.
The authentication/session handling is implemented in an IDispatchMessageInspector which is invoked before the webservice is loaded.
The problem occurred when an application that uses my webservice was online when the application pool was recycled. Then application would then a request to a webservice using the authenticated behavior.
The IDispatchMessageInspector implemention would then try to load the settings, but they have not yet been initialized from the static constructor in the webservice....
Thank you for the answers...
You can use the WCF runtime infrastructure to take care of this for you. Try adding the following attribute to the WebService class:
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.Single)]
I have read a lot about mocking, particularly using Rhino Mocks and have learned that Rhino Mocks can only mock interface methods which are virtual or virtual methods in concrete classes. I have read that the reason for this is because Rhino mocks can't intercept non-virtual methods and this is where I am stuck. What does it mean by intercepting methods? How does intercepting methods actually work with regards to mocking (Rhino Mocks in particular)
Basically the idea is that it creates a 'behind the scenes' class that overrides any virtual or interface methods and plugs in 'mock' code into them.
Highly simplified example/overview
if you have (based on your comment question)
public EmailHelper
{
public virtual int SendEmail( MailMessage message)
{
var server = ConnectToServer();
int statusCode = server.SubmitEmail( message );
return statusCode;
}
}
and then in a test (I forget Rhino's syntax for this, but this is close enough)
var mock = Mocks.CreateMockFor<EmailHelper>();
Expect.Call(mock.SendEmail).Return(5);
behind the scenes it will use reflection to load up the SomeClass Type object, search it for interface implementations and virtual methods and generate a class something like
public MockEmailHelper
{
public override int SendEmail( MailMessage message )
{
return 5;
}
}
So as you can see, when you call the mock version of SendEmail, it wont connect to server etc, it will just do what you told it to, so you can test your code that depends on the 'email module' without actually sending email.
I have a WCF service that generates loads Entity Framework objects (as well as some other structs and simple classes used to lighten the load) and sends them over to a client application.
I have changed 2 of the classes to implement an interface so that I can reference them in my application as a single object type. Much like this example:
Is it Possible to Force Properties Generated by Entity Framework to implement Interfaces?
However, the interface type is not added to my WCF service proxy client thingymebob as it is not directly referenced in the objects that are being sent back over the wire.
Therefore in my application that uses the service proxy classes, I can't cast or reference my interface..
Any ideas what I'm missing?
Here's some example code:
//ASSEMBLY/PROJECT 1 -- EF data model
namespace Model
{
public interface ISecurable
{
[DataMember]
long AccessMask { get; set; }
}
//partial class extending EF generated class
//there is also a class defined as "public partial class Company : ISecurable"
public partial class Chart : ISecurable
{
private long _AccessMask = 0;
public long AccessMask
{
get { return _AccessMask; }
set { _AccessMask = value; }
}
public void GetPermission(Guid userId)
{
ChartEntityModel model = new ChartEntityModel();
Task task = model.Task_GetMaskForObject(_ChartId, userId).FirstOrDefault();
_AccessMask = (task == null) ? 0 : task.AccessMask;
}
}
}
//ASSEMBLY/PROJECT 2 -- WCF web service
namespace ChartService
{
public Chart GetChart(Guid chartId, Guid userId)
{
Chart chart = LoadChartWithEF(chartId);
chart.GetPermission(userId); //load chart perms
return chart; //send it over the wire
}
}
Interfaces won't come across as separate entities in your WSDL - they will simply have their methods and properties added to the object that exposes them.
What you want to accomplish you can do using abstract classes. These will come across as distinct entities.
Good luck. Let us know how you decided to proceed.