Pattern to Add Behaviour using New Methods at Runtime - c#

I would like to be able to use a pattern to add behaviour (by virtue of additional methods/properties) to an existing class at runtime.
This seems very similar to the well-known decorator pattern, however, the examples that I have been able to find of the decorator pattern do not allow for the nested addition of new methods. This is best illustrated with an example:
namespace Decorator {
// classes and types
// - component:
// - concrete component:
// - decorator:
// - concrete decorator:
class Program {
static void Main(string[] args) {
IServer serverA = new Server(); // has database services
IServer serverB = new Server(); // has web services
IServer serverC = new Server(); // has both database services and web services
// add behaviour using the decorator pattern
serverA = new DatabaseServerDecorator(serverA);
serverB = new WebServerDecorator(serverB);
serverC = new DatabaseServerDecorator(serverA);
serverC = new WebServerDecorator(serverA); // note the 2nd level which causes loss of 'awareness' of the DbDecorator
// test restart of servers
serverA.RestartServer();
serverB.RestartServer();
serverC.RestartServer();
// test restart of web services
var webServerB = serverB as WebServerDecorator;
var webServerC = serverB as WebServerDecorator;
webServerB.RestartWebServices();
webServerC.RestartWebServices();
// test restart of database services
var databaseServerA = serverA as DatabaseServerDecorator;
var databaseServerC = serverC as DatabaseServerDecorator; // this will not work (HOW TO FIX??)
databaseServerA.RestartDatabaseServices();
databaseServerC.RestartDatabaseServices();
Console.ReadKey();
}
}
// IComponent
public interface IServer {
void RestartServer();
}
// Component
public class Server : IServer {
public void RestartServer() {
Console.WriteLine("Server restarted.");
}
}
// DecoratorA
public class WebServerDecorator : IServer {
IServer _server;
public WebServerDecorator(IServer server) {
_server = server;
}
public void RestartServer() {
_server.RestartServer();
}
public void RestartWebServices() {
Console.WriteLine("Web services restarted.");
}
}
public class DatabaseServerDecorator : IServer {
IServer _server;
public DatabaseServerDecorator(IServer server) {
_server = server;
}
public void RestartServer() {
_server.RestartServer();
}
public void RestartDatabaseServices() {
Console.WriteLine("Database services restarted.");
}
}
}
(The real code would use "if object is Type" for identification, but this has been removed for conciseness/clarity)
Is this possible? In the example above, it may be possible for a server to have more than one 'service', so it would not be desirable to have to create every possible permutation (which would become unmanageable as the number of services grow).

Calls to Console.WriteLine("database service ..") should belong to RestartServer() as it's logically belongs to "interface contract". That's the goal of Decorator pattern - you decorate behavior of what is provided by interface (but no more). Creating new methods (extending interface contract) is not what Decorator is meant to do. Not sure what you're trying to achieve but maybe you shouldn't over-abstracting it? How about having different interfaces like IWebServer, IDatabaseServer (implementing IServer) and decorate IWebServer, IDatabaseServer instead of IServer?

Related

How to handle event invocation between injected classes in .NET Core Console App

I've a .Net Core(3.1) Console App, that has 2 service classes, one has an event and other listens to it with a handler to that event. I've setup getting the DI containers but the event field is always null, so not able to call its Invoke(). Any pointers on what am I missing in setting up the services in ConfigureServices() that involves event handling. Below is the complete test code:
public class RefreshEventArgs : EventArgs
{
public string RefreshEventData { get; set; }
}
public interface INotifierService
{
event EventHandler<RefreshEventArgs> RefreshEventHandler;
}
public class NotifierService : INotifierService
{
public event EventHandler<RefreshEventArgs> RefreshEventHandler;
public RefreshEventArgs RefreshEventData { get; set; }
// GeneralAppSettings is a POCO class to read all appsettings.json key values.
private readonly IOptions<GeneralAppSettings> myAppSettings;
public NotifierService(IOptions<GeneralAppSettings> appSettings)
{
myAppSettings = appSettings;
}
public void RunInvokingRefreshEvent()
{
RefreshEventData = new RefreshEventArgs();
RefreshEventData.RefreshEventData = "somedata";
// Main problem! In the below line, RefreshEventHandler is null all the time
RefreshEventHandler?.Invoke(this, RefreshEventData);
}
public void SomeBackgroundThreadMonitorsExternalEvents()
{
// Some external events triggers below method
RunInvokingRefreshEvent();
}
}
Refresh Service
public interface IRefreshService
{
void Refresh(RefreshEventArgs eventData = null);
}
public class RefresherService : IRefreshService
{
private readonly IOptions<GeneralAppSettings> myAppSettings;
private readonly INotifierService notify;
public RefresherService(IOptions<GeneralAppSettings> _appSettings, INotifierService _notifyService)
{
myAppSettings = _appSettings;
notify = _notifyService;
notify.RefreshEventHandler += _notify_RefreshEventHandler;
}
private void _notify_RefreshEventHandler(object sender, RefreshEventArgs e)
{
// Call Refresh() based say based on a config value from myAppSettings
Refresh(e);
}
public void Refresh(RefreshEventArgs eventData = null)
{
// final business logic processing based on eventData
}
}
public class GeneralAppSettings // POCO
{
public string SomeConfigKeyInAppSettingsJson { get; set; }
}
Program
class Program
{
public static IConfiguration Configuration { get; set; }
static void Main(string[] args)
{
// read appsettings
var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
// Host builder, setting up container
var host = Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddConfiguration(Configuration);
})
.ConfigureServices((context, services) =>
{
services.Configure<GeneralAppSettings>(Configuration.GetSection("GeneralAppSettings"));
services.AddSingleton<INotifierService, NotifierService>();
services.AddSingleton<IRefreshService, RefresherService>();
})
.Build();
// Need to get NotifierService instance to run some initial logic, so using ActivatorUtilities
var svc = ActivatorUtilities.GetServiceOrCreateInstance<NotifierService>(host.Services);
svc.SomeBackgroundThreadMonitorsExternalEvents();
// Need to get RefresherService instance to have initial Refresh logic so using ActivatorUtilities
var refresh = ActivatorUtilities.GetServiceOrCreateInstance<RefresherService>(host.Services);
refresh.Refresh(null);
// need to keep this main thread alive
Thread.Sleep(Timeout.Infinite);
}
}
When you request something from the DI container, you must request the "Service" type (the interface or first/only generic argument). If you request a type that's not been registered and you use ActivatorUtilities, it will create an instance if and only if all the types required to construct it are available. What's happening to you is you are getting two distinct objects (one registered as the interface and one pseudo-registered as the concrete type)! It doesn't matter that your class implements the interface and you've used it as the "Implementation" type in the registration. DI is always based on the service type and you've not registered any services of type NotifierService directly.
Your problem is that you have a weird coupling between your classes and the method you want to call on NotifierService isn't actually part of the interface. The usual trick would be to just register and request the concrete type as the service type:
services.AddSingleton<NotiferService>();
//...
var notifier = services.GetService<NotifierService>();
That would work, except now you haven't registered INotifierService for injection into the RefresherService.
Never fear, we have a work around. Register the concrete type as a singleton and then use a factory to register the interface:
// register the concrete type directly
services.AddSingleton<NotifierService>();
// use a factory to register the interface
services.AddSingleton<INotifierService>(sp => sp.GetRequiredService<NotifierService>());
Now, the same instance will be returned whether you are requesting the interface or the concrete type. You no longer need to use ActivatorUtilities either (in fact you shouldn't)--you can now use the host's services directly:
var notifier = host.Services.GetRequiredService<NotifierService>();
notifier.SomeBackgroundThreadMonitorsExternalEvents();
All that said, you're project is a perfect candidate for an IHostedService/BackgroundService. You can restructure it a bit (splitting NotifierService into two classes: one with just the event and the other for the background service) such that you'll then only be dealing with interfaces and you'd be able to actually call Host.Run() which will in turn wait for shutdown. This is the standard pattern for things like this, rather than abusing the Host simply for the DI container and including the weird Thread.Sleep.

How to use DI in WPF to having a new istance without ask to container

i'm trying to develop from scratch a WPF app with the use of Simpleinjector as a IOC container.
I'm new on this topic and i have some issue regards lifetime of object and hot use them correctly.
I started the app by following the WPF integration guide on simpleinjector manual.
But i don't understand how to receive a new instance every time a service needed it
As i ask in my previous post i need to receive a new unitOfWork every time a service need it.
as #Steven say on my previous post
Do note that transient means "allways a new instance is resolved when it is requested from the container." If you're not requesting it again, you will be operating on the same instance, which might explain the ObjectDisposedException.
In the other post i found a solutin but i think it's a little bit over-complicated and it's to create a factory and inject this instead of the instance because i want to call the container.getInstance only on the startup method and not on the service by passing the container as a dependency
It's the only way i have to achieve this or there is something that i don't understand on how to develop in DI way?
Example of code:
public class HeaderViewModelFactory : IWpfRadDispenserViewModelFactory<HeaderviewModel>
{
private readonly ProductionService _service;
public HeaderViewModelFactory(ProductionService service)
{
_service = service;
}
public HeaderviewModel CreateViewModel()
{
return new HeaderviewModel(_service);
}
}
public class HeaderviewModel : ViewModelBase
{
private readonly ProductionService _service;
public HeaderviewModel(ProductionService service)
{
_service = service;
CreateData();
}
private void CreateData()
{
_service.CreateTestCycle();
}
}
public class CycleService : GenericDataService<Cycle>
{
private readonly IUnitOfWork<WpfRadDispenserDbContext> _uowContext;
public CycleService(IUnitOfWork<WpfRadDispenserDbContext> uowContext)
: base(uowContext)
{
_uowContext = uowContext;
}
public void CreateTestCycle()
{
var cycleDataService = new GenericDataService<Cycle>(_uowContext);
var vialDataService = new GenericDataService<Vial>(_uowContext);
Cycle c = new Cycle();
c.BatchName = "test";
Vial v = new Vial();
v.Name = "Test Vial";
c.Vials.Add(v);
_uowContext.CreateTransaction(IsolationLevel.ReadCommitted);
try
{
vialDataService.Create(v);
_uowContext.Persist();
var list = vialDataService.GetAll();
cycleDataService.Create(c);
_uowContext.Persist();
_uowContext.Commit();
}
catch (Exception e)
{
Console.WriteLine(e);
_uowContext.RollBack();
throw;
}
finally
{
_uowContext.Dispose();
}
}
}
private static Container Bootstrap()
{
// Create the container as usual.
var container = new Container();
// Register your types:
// Register your windows and view models:
container.Register<WpfRadDispenserDbContextFactory>(Lifestyle.Transient);
container.Register<IUnitOfWork<WpfRadDispenserDbContext>,WpfRadDispenserUOW>();
container.Register(typeof(CycleService));
container.Register<IWpfRadDispenserViewModelFactory<ProductionViewModel>,
ProductionViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<AnagraphicViewModel>,
AnagraphicsViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<HeaderviewModel>,
HeaderViewModelFactory>(Lifestyle.Transient);
container.Register<IViewModelAbstractFactory,
ViewModelAbstractFactory>(Lifestyle.Transient);
container.Register<INavigator, Navigator>(Lifestyle.Transient);
container.Register<MainWindowViewModel>();
container.Register<MainWindow>();
//container.Options.EnableAutoVerification = false;
//container.Verify();
return container;
}
in this way every time i create a new viewmodel i receive the same service and ovviously the dbcontext it's not present anymore because disposed.
This is not the rela code but only an example that i made to understand how DI works.
Using Abstract Factory pattern is the most common and recommended approach. Using the container in your application directly is widely considered an anti-pattern, like the Service Locator (Service Locator is an Anti-Pattern) for a very good reason.
Abstract factory allows instantiation of objects without introducing a tight coupling to the actual implementation that knows how to create specific instances.
Most IoC frameworks support this pattern natively. Most of the time they provide the generic interface for the factory. You register the instance (the product) with the container and the framework will export a ready-to use factory for you. You add the dependency to this framework interface to your object e.g. constructor. Then you register the generic factory interface. The framework will automatically create the instance of the factory and inject it into the relevant instances e.g., via constructor.
I am not too familiar with Simple Injector, but the framework really keeps things simple. There is no such code generation.
But the pattern is very simple (that's why this is so easy to automate) and in no way complicated.
Example
The interface required to dynamically create the instances of type TInstance:
interface IFactory<TInstance>
{
TInstance Create();
}
The implementation of this factory:
class SaveItemFactory : IFactory<ISaveItem>
{
ISaveItem Create() => new SaveItem();
}
The type that needs to create a dependency dynamically:
interface IItemManager {}
class ItemManager : IItemManager
{
IFactory<ISaveItem> SaveItemFactory { get; }
public ItemManager(IFactory<ISaveItem> itemFactory) => this.SaveItemFactory = itemFactory;
public void SaveData(object data)
{
ISaveItem saveItem = this.SaveItemFactory.Create();
saveItem.SetData(data);
}
}
Configure the container:
public void Run()
{
var container = new SimpleInjector.Container();
container.Register<IFactory<ISaveItem>, SaveItemFactory>(Lifestyle.Singleton);
container.Register<IItemManager, ItemManager>(Lifestyle.Singleton);
IItemManager itemManager = container.GetInstance<IItemManager>();
itemManager.SaveData("Some Data");
}

Should I define methods as static in class library to use in Console Application

Scenario: I have a console application which references couple of class libraries. ClassLibEmployee pulls the data from SQL database and returns a List. I need to loop through the list of Employee's and send that to a WebAPI and update SQL DB with status. I created ClassLibPay which a wrapper for WebAPI.
ClassLibEmployee.EmployeeData ed = new ClassLibEmployee.EmployeeData();
var elist = ed.PullEmployees();
foreach (Employee e in elist) {
bool stat = ClassLibPay.ServiceWrap.Sendtopay(e.Id, e.Name, e.Pay, e.ExemptFlag, e.Hours);
ed.ChageStatus(e.Id, e.Name, e.Pay, e.ExemptFlag, e.Hours, stat);
}
In ClassLibEmployee, I defined class as public class EmployeeData
In ClassLibPay, I defined class as public static class ServiceWrap
Questions:
since I will be calling ChangeStatus method in EmployeeData for each employee, should that be a static class?
ServiceWrap is calling a service, is there a way to avoid creating instance of the service, for every Sendtopay call?
Console App
--References ClassLibEmployee
public class EmployeeData
{
public List<Employee> PullEmployees()
{
}
}
ConsoleApp
--References ClassLibPay
-- ClassLibPay calls a WebAPI
public static class ServiceWrap
{
public static bool Sendtopay(int id, string name, decimal pay, bool flg, int hours)
{
using (EDataSvc service = new EDataSvc())
{
service.serviceMethod(id,name,pay,flg,hours);
}
}
}
To prevent creating every time class, you definitely should move to DI way as Michael said.
This is very simple example how to use DI with console application based on Autofac library. Below we have Main console application and two classes where one is our wrapper(where maybe you want to prepare your data, and eDataService which should just send data to back-end. We register both classes as PerLifeTimeScope(here, this is singleton's - in another words have only one instance if we get it from the DI container). Of course you can choose ready frameworks with already integrated DI containers.
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
builder.RegisterType<EDataSvc>().InstancePerLifetimeScope();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<MyService>();
service.MakeRequestAsync("test");
}
}
}
public class EDataSvc
{
public void SendRequestAsync()
{
//TODO:Send request
}
}
public class MyService : IMyService
{
private EDataSvc _eDataService;
public void MakeRequestAsync(EDataSvc eDataSvc)
{
_eDataService = eDataSvc;
}
public void MakeRequestAsync(string parameter)
{
//TODO prepare your data or additional logic
_eDataService.SendRequestAsync();
}
}
public interface IMyService
{
void MakeRequestAsync(string parameter);
}

Use Castle.Windsor with SSW Data Onion for Entity Framework 6

I'm working on integrating a legacy database with Asp.Net Zero. I created the model classes using EntityFramework Reverse POCO Generator in a separate Models class library project. I also reversed engineered the DbContext into a separate Data class library project. I would like to use the Data Onion framework for my repositories and unit of work. When I use the recommended IOC container Autofaq my Test Winform application works correctly.
However, the Web Project utilizes Castle.Windsor. I'm uncertain on how to do the wire-up.
I'm creating a new container called ClientDesktopContainer:
internal class ClientDesktopContainer : WindsorContainer
{
public ClientDesktopContainer()
{
RegisterComponents();
}
private void RegisterComponents()
{
var connectionstring = ConfigurationManager.ConnectionStrings["MyDbContext"].ConnectionString;
// Data Onion
Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>()
.DependsOn(new DbContextConfig(connectionstring, typeof(MyDbContext), new MigrateToLatestVersion(new Seeder())));
Component.For<IDbContextScope>().ImplementedBy<DbContextScope>();
Component.For<IDbContextScopeFactory>().ImplementedBy<DbContextScopeFactory>();
Component.For<IAmbientDbContextLocator>().ImplementedBy<AmbientDbContextLocator>();
Component.For<IDbContextReadOnlyScope>().ImplementedBy<DbContextReadOnlyScope>();
// Data Onion Unit of Work
Component.For<IRepositoryLocator>().ImplementedBy<RepositoryLocator>();
// Component.For<IRepositoryResolver>().ImplementedBy<CastleWindsorRepositoryResolver>();
Component.For<IUnitOfWorkFactory>().ImplementedBy<UnitOfWorkFactory>();
Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>();
Component.For<IReadOnlyUnitOfWork>().ImplementedBy<IReadOnlyUnitOfWork>();
// Custom
Component.For<IRepository<Enrollment>>()
.ImplementedBy<BaseRepository<Enrollment, MyDbContext>>();
}
My application invocation code is Program:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
IoC.Initialize(new ClientDesktopContainer());
var dbContextScopeFactor = IoC.Resolve<IDbContextScopeFactory>();
using (var dbReadOnly = dbContextScopeFactor.CreateReadOnly())
{
var context = dbReadOnly.DbContexts.Get<MyDbContext>();
var individuals = context.Enrollments.ToList();
foreach (var individual in individuals)
{
// do stuff
}
}
Application.Run(new ViewMain());
}
}
I created a static IOC:
public static class IoC
{
private static IWindsorContainer _container;
public static void Initialize(IWindsorContainer container)
{
_container = container;
}
public static T Resolve<T>()
{
try
{
return _container.Resolve<T>();
}
catch
{
throw;
}
}
}
The Data Onion documentation mentions registering a custom Resolver for IRepositoryResolver.
I created a CastleWindsorRepositoryResolver:
public class CastleWindsorRepositoryResolver : IRepositoryResolver
{
public IRepository<TEntity> Resolve<TEntity>() where TEntity : class
{
// TODO: Resolve wire-up goes here
throw new System.NotImplementedException();
}
}
I'm receiving a ComponentNotFoundExpection:
Updated to fix constructor parameter for DbContextFactory (to RegisterComponents method):
var dbContextConfig = new DbContextConfig[]
{
new DbContextConfig(
connectionString,
typeof(MyDbContext),
new MigrateToLatestVersion(new Seeder())
)
};
// Data Onion
Register(Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>()
.DependsOn(Dependency.OnValue<DbContextConfig[]>(dbContextConfig)));
Add call to Register in:
internal class ClientDesktopContainer : WindsorContainer
{
public ClientDesktopContainer()
{
RegisterComponents();
}
private void RegisterComponents()
{
var connectionstring = ConfigurationManager.ConnectionStrings["MyDbContext"].ConnectionString;
/* HERE CALL TO REGISTER: */
this.Register(
// Data Onion
Component.For<IDbContextFactory>().ImplementedBy<DbContextFactory>()
.DependsOn(new DbContextConfig(connectionstring, typeof(MyDbContext), new MigrateToLatestVersion(new Seeder()))),
Component.For<IDbContextScope>().ImplementedBy<DbContextScope>(),
Component.For<IDbContextScopeFactory>().ImplementedBy<DbContextScopeFactory>(),
Component.For<IAmbientDbContextLocator>().ImplementedBy<AmbientDbContextLocator>(),
Component.For<IDbContextReadOnlyScope>().ImplementedBy<DbContextReadOnlyScope>(),
// Data Onion Unit of Work
Component.For<IRepositoryLocator>().ImplementedBy<RepositoryLocator>(),
// Component.For<IRepositoryResolver>().ImplementedBy<CastleWindsorRepositoryResolver>(),
Component.For<IUnitOfWorkFactory>().ImplementedBy<UnitOfWorkFactory>(),
Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>(),
Component.For<IReadOnlyUnitOfWork>().ImplementedBy<IReadOnlyUnitOfWork>(),
// Custom
Component.For<IRepository<Enrollment>>()
.ImplementedBy<BaseRepository<Enrollment, MyDbContext>>() );
}
Without Register you are just creating registration object without actually putting types in container. Another thing that may help, by default Castle will register components as singletons add LifestyleTranscient or PerWebRequest to your UnitOfWork registrations.

How to mock a web service

Do I have to rewrite my code to do this into an interface? Or is there an easier way? I am using Moq
What I usually do is build a wrapper or an adapter around my web service and just mock that.
for instance:
public class ServiceAdapter: IServiceAdapter
{
public void CallSomeWebMethod()
{
var someService = new MyWebService();
someService.SomeWebMethod();
}
}
Then I just stub the service adapter.
[Test]
public void SomeMethod_Scenario_ExpectedResult()
{
var adapterMock = new Mock<IServiceAdapter>();
//do your test
}
been writing a couple of responses about unit testing and mocking lately. I wrote elsewhere that it's important to ask yourself what exactly are you testing. Regarding your particular situation, I would hope the answer is "I am testing the business logic my WebService is exposing", and not "I am testing my WebService" - there's a difference.
If your concerns are server-side
You do not need to test WebServices in general. MS has already done that. Millions of people have done that. Testing the transport layer, the protocol, the definition of WebServices is a waste of time.
You need to target your business logic. The best way to do this is to separate your business logic from your WebService. Consider the following
public class MyWebSevice : System.Web.Services.WebService
{
private AuthenticationService _auth = new AuthenticationService ();
private int _count = 0;
[WebMethod]
public string DoSomething ()
{
// embedded business logic, bad bad bad
if (_auth.Authenticate ())
{
_count++;
}
return count.ToString ();
}
}
there is no way to test that logic without invoking the WebService directly. What you really want is
public class MyService
{
// keeners will realise this too should be injected
// as a dependency, but just cut and pasted to demonstrate
// isolation
private AuthenticationService _auth = new AuthenticationService ();
private int _count = 0;
public string DoSomething ()
{
if (_auth.Authenticate ())
{
_count++;
}
return count.ToString ();
}
}
in prod
// this web service is now a consumer of a business class,
// no embedded logic, so does not require direct testing
public class MyWebSevice : System.Web.Services.WebService
{
private readonly MyService _service = new MyService ();
[WebMethod]
public string DoSomething ()
{
_service.DoSomething ();
}
}
in test
// test business logic without web service! yay!
[Test]
public void Test_DoSomething ()
{
MyService service = new MyService ();
string actual = service.DoSomething ();
// verify results
}
managing dependencies [like the AuthenticationService member] is a separate issue. However, making your WebMethods simple passthroughs to proper underlying business classes and removing logic from them completely, allows you to target "real" user code as opposed to the plumbing of your typical WebService implementation.
If your concerns are client-side
You have a business component calling a webservice, and I agree that you don't want to create a client for unit testing.
public partial class MyWebService :
System.Web.Services.Protocols.SoapHttpClientProtocol
{
...
public string DoSomething () { ... }
}
public class MyClient
{
public void CallService ()
{
MyWebService client = new MyWebService ();
client.DoSomething ();
}
}
Here, you have dependency issues, namely you cannot test MyClient.CallService without instantiating and hosting your WebService. Especially disconcerting if you do not own or host said remote service. In this case, yes, you should write against an interface - once again to separate and isolate business logic.
public interface IMyWebService
{
string DoSomething ();
}
public class MyWebServiceWrapper : IMyWebService
{
public string DoSomething ()
{
MyWebService client = new MyWebService ();
client.DoSomething ();
}
}
public class MyClient
{
private readonly IMyWebService _client = null;
public MyClient () : this (new MyWebServiceWrapper ()) { }
public MyClient (IMyWebService client)
{
_client = client;
}
public void CallService ()
{
_client.DoSomething ();
}
}
in test
[Test]
public void Test_CallService ()
{
IMyWebService mockService = null;
// instantiate mock with expectations
MyClient client = new MyClient (mockService);
client.CallService ();
// verify results
}
In general, if a class's dependencies are in-proc services, the decision to apply a pattern like Dependency Injection [DI] or Inversion of Control [IoC] is up to you - and your desire to isolate and unit test these services will inform your design. However, if a class's dependencies cross a process boundary, eg Database or WebService, I highly recommend applying these patterns as we did above.
Really, it's just plain old interface development. You probably already see how it pays off.
:)
I blogged about this a long time ago. Basically using partial classes and a bit of effort (either automated or manual, depending on how often you're going to change the web service) you can make the web service proxy class implement an interface. You can then mock it as normal.
there is an easy way.
for example if we have WebService class with the name DbService,
first create an interface for it (ex. IService), and use this interface for mocking, then add a class to your project and put this:
public partial class DbService:IService {
}
leave class empty, because of web services are partial class we use this implementation.
(previously

Categories

Resources