Uniform how data is fetched by sharing implementation in nuget package - c#

How do I abstract the connection to my database away?
I am currently working on a nuget package, that sort of unify the way data is retrieved from the database,
thus ensuring that data is collected in a similar manner, regardless which service inherits it.
I though seem to be a bit confused of whether my inherited class, and the properties will be assessible for MyService?
and instantiated correctly?
Here is an example:
public class DataService : IDataservice
{
private readonly CosmosClient client;
public TestClass(CosmosClient client)
{
var kvUrl = Environment.GetEnvironmentVariable("KEY_VAULT_URL");
var secretclient = new SecretClient(new Uri(kvUrl), new DefaultAzureCredential());
var accountEndpoint = secretclient.GetSecret("AccountEndpoint-CosmosDb");
var accountKey = secretclient.GetSecret("AccountKey-CosmosDb");
this.client = new CosmosClientBuilder(accountEndpoint.Value.Value, accountKey.Value.Value).Build();
}
public IDictionary<string, object> GetForm(Guid id)
{
//Contains custom code for fetching form
//Processing fetched form'
//Return form
}
public object GetFormField(string propertyName)
{
//Contains custom code for fetching field
//Processing fetched field
//Return field
}
public string TestString()
{
return "Hello web";
}
}
public class MyService : DataService
{
public MyService()
{
}
public IDictionary<string, object> GetForm(Guid id) => return parent.GetForm(Guid id)
public object GetFormField(string propertyName) => return parent.GetFormField(string propertyName)
public override object GetFormField(string propertyName)
{
return "Hello new world";
}
}
does Myservice have an instantiated version of the CosmosClient?
Is GetForm and GetFormField accessible to MyService - and is it possible to explictly state when an inherited method is overridden as above?
and is this even a good idea? - I feel like I am creating an unessary layer, to ensure that data is fetched uniformly by making a class that everyone can inherit.

I think you could do something like this:
public class TestClass
{
private CosmosClient _client;
private SecretClient _secretClient;
public string kvUrl { get => Environment.GetEnvironmentVariable("KEY_VAULT_URL"); }
public SecretClient secretClient {
get
{
return _secretClient ?? (_secretClient = new SecretClient(new Uri(kvUrl), new DefaultAzureCredential()));
}
}
public KeyVaultSecret accountEndpoint {
get
{
return _secretClient.GetSecret("AccountEndpoint-CosmosDb");
}
}
public KeyVaultSecret accountKey {
get
{
return _secretClient.GetSecret("AccountKey-CosmosDb");
}
}
public CosmosClient client {
get
{
return _client ?? (_client = new CosmosClientBuilder(accountEndpoint.Value, accountKey.Value).Build());
}
}
}

Why dont you make an abstract class for DataService, and set the secrets/connections from the derived classes.
as
public abstract class DataService
{
public DataService(CosmosClient client)
{
var kvUrl = Environment.GetEnvironmentVariable("KEY_VAULT_URL");
var secretclient = new SecretClient(new Uri(kvUrl), new DefaultAzureCredential());
var accountEndpoint = secretclient.GetSecret("AccountEndpoint-CosmosDb");
var accountKey = secretclient.GetSecret("AccountKey-CosmosDb");
this.client = new CosmosClientBuilder(accountEndpoint.Value.Value, accountKey.Value.Value).Build();
}
// your abstract methods here to be implementd by derived classes
}
class some_derived_class:DataService{
some_derived_class:DataService(CosmosClient client):base(client){}
}

Related

Fake IMongoQueryable with FakeItEasy

I'm developing an API which communicates with MongoDB and I need to create some statistics from one collection. I have the following service:
public class BoxService : IBoxService
{
private readonly IMongoCollection<Box> _boxCollection;
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
_boxCollection = mongoDatabase.GetCollection<Box>(dbSettings.Value.BoxCollectionName);
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var results = await _boxCollection.AsQueryable()
.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty })
.ToListAsync();
// More calculations with the results list
return boxNumberStatisticsList;
}
}
And the following test:
public class BoxServiceTest
{
private readonly IMongoCollection<Box> _boxCollection;
private readonly List<Box> _boxes;
private readonly IBoxService _boxService;
public BoxServiceTest()
{
_boxCollection = A.Fake<IMongoCollection<Box>>();
_boxes = new List<Box> {...};
var mockOptions = A.Fake<IOptions<DbSettings>>();
var mongoClient = A.Fake<IMongoClient>();
var mongoDb = A.Fake<IMongoDatabase>();
A.CallTo(() => mongoClient.GetDatabase(A<string>._, default)).Returns(mongoDb);
A.CallTo(() => mongoDb.GetCollection<Box>(A<string>._, default)).Returns(_boxCollection);
_boxService = new BoxService(mockOptions, mongoClient);
}
}
This is working so far, the BoxService is created with the fake parameters and I can test other functionalities of the service (FindAll, FindById, Create, etc.) but how can I test the GetBoxNumberStatisticsAsync function? I can't fake the AsQueryable because it's an extension method.
As you've noted, you can't fake an extension method. This question is asked every once in a while. For example, see Faking an Extension Method in a 3rd Party Library. There are a few approaches:
if the static method is simple enough, to divine what it does and fake the non-static methods that it calls
add a layer of indirection: wrap the call to the extension method in an interface that you can fake
don't fake the database. Instead, replace it with some in-memory analogue, if one exists (I don't know what's available for Mongo)
Here is what I ended up with. A base interface for all my services:
public interface IBaseService<T>
{
//generic method definitions for all services: Findall, FindById, Create, Update
}
An abstract class to have a generic constructor:
public abstract class BaseService<T> : IBaseService<T>
{
protected BaseService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient, string collectionName)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
Collection = mongoDatabase.GetCollection<T>(collectionName);
}
protected IMongoCollection<T> Collection { get; }
// abstract method definitions for IBaseService stuff
public virtual async Task<List<T>> CollectionToListAsync()
{
return await Collection.AsQueryable().ToListAsync();
}
}
An interface for my BoxService:
public interface IBoxService : IBaseService<Box>
{
public Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync();
}
The service itself:
public class BoxService : BaseService<Box>, IBoxService
{
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
: base(dbSettings, mongoClient, dbSettings.Value.BoxCollectionName)
{
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var list = await CollectionToListAsync();
var results = list.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty }).ToList();
//...
return boxNumberStatisticsList;
}
}
And finally the test:
public async Task GetBoxNumberStatisticsAsync_ReturnsStatistics()
{
// Arrange
var expected = new List<BoxStatisticsDto> {...};
var fakeService = A.Fake<BoxService>(options => options.CallsBaseMethods());
A.CallTo(() => fakeService.CollectionToListAsync()).Returns(_boxes);
// Act
var boxList = await ((IBoxService)fakeService).GetBoxNumberStatisticsAsync();
// Assert
}
I'm not a huge fan of making the CollectionToListAsync public, but nothing really worked for me here. I tried creating IQueryable and IEnumerable from my list and convert them to IMongoQueryable but no success. I also tried faking the IMongoQueryable but I couldn't execute the Select on it as it gave an error that the 'collectionNamespace' can't be null and the CollectionNamespace can't be faked, because it's a sealed class.

How to make the ActivatorUtilities.CreateInstance method use a different constructor?

Is there a way the tell the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method to try to use other constructors if the first one can't be constructed?
I have a class with multiple constructors:
public ViewModelB(SomeDependency someDependency): this one only takes SomeDependency which is registered in a DI container
public ViewModelB(SomeDependency someDependency, GetUserRequest request): this one takes SomeDependency which is registered in a DI container and a GetUserRequest which has to be passed in manually
And I'm trying to activate them and resolve dependencies like so:
IServiceProvider serviceProvider; //this gets passed from somewhere
Guid userId; //this gets passed manually by the caller
//works
var instanceAWithoutParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider);
//works
var instanceAWithParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider, new[] { new GetUserRequest { UserId = userId } });
//does NOT work, it tries to use the first constructor and fails
var instanceBWithoutParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider);
//works
var instanceBWithParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider,, new[] { new GetUserRequest { UserId = userId } });
The activation of instanceBWithoutParams fails because it can't resolve the request parameter. It tries to use the first constructor and doesn't check other ones when the activation fails.
Here's what the services look like, they're the same with one difference: the order of the constructors.
public class ViewModelA
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelA(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public ViewModelA(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
}
public class ViewModelB
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelB(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
public ViewModelB(SomeDependency someDependency)
{
_someDependency = someDependency;
}
}
public class GetUserRequest
{
public Guid UserId { get; set; }
}
Thanks.
I struggled with the same issue. Eventually I came up with this solution:
I would use something like a factory which is able to construct ServiceB by calling a method.
For example:
var serviceBFactory = ActivatorUtilities.CreateInstance<ServiceBFactory>(serviceProvider);
var instanceBWithoutParams = serviceBFactory.CreateServiceB();
var instanceBWithParams = serviceBFactory.CreateServiceB(new Request());
This way you keep you DI clean. But this means that the ServiceBFactory need to know which services need to be injected in a ServiceB. (so that will be a tight coupling) They come as a package.
I've chosen to re-design the view models instead of trying to pass optional parameters next to services from DI (thanks to Steven for the helpful articles: 1 and 2).
There also seems to be no way of making the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method try other constructors after one fails, so here's what my edited solution looks like.
I've moved the initialization of the optional parameter out of the constructor, that way I only have one constructor that only takes injectables. The parameter is then passed separately via the TakeParameter method. The only downside I can think of is that the parameter can no longer be readonly and I can live with that.
My custom activator utility:
public interface IAcceptParameter<T>
{
void TakeParameter(T parameter);
}
public static class CustomActivator
{
public static T CreateInstance<T>()
{
return ActivatorUtilities.CreateInstance<T>(_serviceProvider);
}
public static T CreateInstanceWithParam<T, K>(K parameter) where T : IAcceptParameter<K>
{
var instance = ActivatorUtilities.CreateInstance<T>(_serviceProvider);
instance.TakeParameter(parameter);
return instance;
}
}
Changed view model
public class SomeViewModel : IAcceptParameter<Guid>
{
private readonly SomeDependency _someDependency;
private Guid? _userId;
public SomeViewModel(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public void TakeParameter(Guid parameter){
_userId = parameter;
}
}
How I use it
var instanceWithoutParam = CustomActivator.CreateInstance<SomeViewModel>(serviceProvider);
Guid userId;
var instanceWithParam = CustomActivator.CreateInstanceWithParam<SomeViewModel, Guid>(serviceProvider, userId);
Let say you have a class like this:
public class a
{
public string p { get; set; }
public a()
{
p = "default constructor";
}
public a(string pv)
{
p = pv;
}
}
You can use .GetConstructor method to use a specific constructor:
public class Program
{
static void Main(string[] args)
{
var c = typeof(a).GetConstructor(new Type[] { typeof(string) });
if (c != null)
{
var myA = (a)c.Invoke(new object[] { "new value" });
Console.WriteLine($"Value of p is {myA.p}");
}
}
}

C# Possible to attach an Object to a method call without having it as a parameter?

I am designing a program with AOP architecture(postsharp) that will intercept all method calls but I need a way to attach a class to every call. The problem is I don't want to have to pass the class explicitly in every single method call. So is there a way to attach a class to a method call in C#?
For example, In angular I can use a custom interceptor to attach anything I want to a header for every outgoing call. This saves down on repeating code. Is there anything like this in C#?
#Injectable()
export class CustomInterceptor implements HttpInterceptor {
constructor() { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({ withCredentials: true });
return next.handle(request);
}
}
This is my interface in C#
public class Wrapper: IMyInterface
{
private IMyInterface_wrapped;
public Wrapper(IMyInterface caller)
{
_wrapped = caller;
}
public FOO GetUserStuff(string userName)
{
return _wrapped.GetUserStuff(req);
}
}
}
Is there a way that I can call the interface like this
var wrapper = new Wrapper(new MyInterface());
LoginRequest req = new LoginRequest <------ this needs to be attached to every single method call
{
ClientId = "ABCDEFG",
ClientSecret = "123456"
};
wrapper.GetUserStuff("Username", req); <------- My interface only takes one argument.
wrapper.GetUserStuff("UserName").append(req) <----of course this doesn't work either
Is there a way that I can call the interface method and attach the object to it without actually implementing it in the interface?
Basically what you want is - whenever the wrapper.GetUserStuff method gets called, a LoginRequest object be available to the Wrapper class object.
But as you answered in the comment section, the value for ClientId and ClientSecret don't change. Then you can avoid the whole hassle of creating the LoginRequest object outside each time and passing it inside as a method parameter by simply creating the LoginRequest object inside the Wrapper class -
public class Wrapper : IMyInterface
{
private IMyInterface _wrapped;
private LoginRequest _req;
public Wrapper(IMyInterface caller)
{
_wrapped = caller;
_req = new LoginRequest { ClientId = "ABCDEFG", ClientSecret = "123456" };
}
public int GetUserStuff(string userName)
{
return _wrapped.GetUserStuff(_req);
}
}
Usually, you will store the ClientId and ClientSecret values somewhere else (instead of hard coding them) and read them accordingly.
And, if you don't have access to the LoginRequest class from the Wrapper class (may be its on a separate layer/project that doesn't have the required assembly reference), then you can declare a class like ClientInfo and use it like -
public class ClientInfo
{
public string UserName { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
}
public class Wrapper : IMyInterface
{
private IMyInterface _wrapped;
private ClientInfo _info;
public Wrapper(IMyInterface caller)
{
_wrapped = caller;
_info = new ClientInfo { ClientId = "ABCDEFG", ClientSecret = "123456" };
}
public int GetUserStuff(string userName)
{
_info.UserName = userName;
return _wrapped.GetUserStuff(_info);
}
}
then the caller can create the LoginRequest object from the ClientInfo passed to it.
To slightly alter #atiyar's approach you can use an accessor. This is a generic version of what is used in core for the HTTPAccessor. The AsyncLocal will be set once for the main thread and then propagate to any threads spawned.
public class GenericAccessor<T> where T : class
{
private static AsyncLocal<Holder<T>> _current = new AsyncLocal<Holder<T>>();
public T Value
{
get => _current.Value?.Context;
set
{
var holder = _current.Value;
if (holder != null)
{
// Clear current trapped in the AsyncLocals, as its done.
holder.Context = null;
}
if (value != null)
{
// Use an object indirection to hold the in the AsyncLocal,
// so it can be cleared in all ExecutionContexts when its cleared.
_current.Value = new Holder<T> { Context = value };
}
}
}
private class Holder<T>
{
public T Context;
}
}
With the implementation
public class ClientInfo
{
public string ClientId { get; set; }
public string ClientSecret { get; set; }
}
public class UserInfo: ClientInfo
{
public UserInfo(ClientInfo clientInfo)
{
this.ClientId = clientInfo.ClientId;
this.ClientSecret = clientInfo.ClientSecret;
}
public string UserName { get; set; }
}
public interface IClientInfoAccessor
{
ClientInfo ClientInfo { get; set; }
}
public class ClientInfoAccessor : GenericAccessor<ClientInfo>, IClientInfoAccessor
{
public ClientInfo ClientInfo{ get => Value; set => Value = value; }
}
public class Wrapper: IMyInterface
{
private IMyInterface _wrapped;
private IClientInfoAccessor _accessor;
public Wrapper(IMyInterface caller, IClientInfoAccessor accessor)
{
_wrapped = caller;
_accessor = accessor;
}
public int GetUserStuff(string userName)
{
var req = new UserInfo(_accessor.ClientInfo);
req.UserName = userName;
return _wrapped.GetUserStuff(req);
}
}
All that you would need to do is to set the ClientInfo in middleware for each operation and you can use the accessor anywhere even in singletons.
Via DI container you can easily inject the IOption<> interface to the class constructor with:
public class Wrapper: IMyInterface
{
private IMyInterface_wrapped;
private MySettings _mySettings;
public Wrapper(IMyInterface caller, IOptions<MySettings> mySettings)
{
_wrapped = caller;
_mySettings = mySettings.Value;
}
private LoginRequest GetLoginRequest()
{
return new LoginRequest
{
ClientId = _mySettings.ClientId,
ClientSecret = _mySettings.ClientSecret
};
}
public FOO GetUserStuff(string userName)
{
return _wrapped.GetUserStuff(GetLoginRequest());
}
}
You can make it a static class and call a static method whenever it's needed. Or if you want to make it like in Angular you can add it to the pipeline (Startup Configure method):
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
LoginRequest req = new LoginRequest
{
ClientId = "ABCDEFG",
ClientSecret = "123456"
};
context.Response.Headers["ClientId"] = "ABCDEFG";
await next();
});
}

(XF) Can only call API value from one class

So I got these classes (JsonData are just a few classes with getters and setters for the Json value from the API):
GetSetJsonData:
class GetSetJsonData
{
HttpClient client;
#region SuccesLogin
JsonData.SuccesLogin.RootObject succesLogin;
JsonData.SuccesLogin.Session session;
JsonData.SuccesLogin.Data2 data2;
JsonData.SuccesLogin test;
#endregion
#region CompanyData
JsonData.CompanyData.RootObject companyDataMatchPage;
JsonData.CompanyData.RootObject companyDataMyNetwork;
JsonData.CompanyData.RootObject companyDataAllCompanies;
#endregion
//uristrings for connecting
string uriLoginString = "url";
string uriGetCompanies = "url";
public string sessionString { get; set; }
public bool MakeConnection(string email, string password)
{
succesLogin = new JsonData.SuccesLogin.RootObject();
session = new JsonData.SuccesLogin.Session();
data2 = new JsonData.SuccesLogin.Data2();
var userdata = new JsonData.UserLogin.Login()
{
userdata = new JsonData.UserLogin.Userdata()
{
user_email = email,
user_password = password
}
};
var content = new StringContent(JsonConvert.SerializeObject(userdata), Encoding.UTF8, "application/json");
client = new HttpClient();
var response = client.PostAsync(uriLoginString, content).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
succesLogin = JsonConvert.DeserializeObject<JsonData.SuccesLogin.RootObject>(responseString);
if (succesLogin.success == null)
{
return false;
}
else
{
session = succesLogin.success.data.session;
sessionString = JsonConvert.SerializeObject(session);
data2 = succesLogin.success.data.data;
return true;
}
//implement failure system
}
//testing only
public void Test()
{
sessionString = JsonConvert.SerializeObject(session);
}
}
LoginPage:
public partial class LoginPage : ContentPage
{
//DummyData DD = new DummyData();
MasterDetailPageSetup masterDetail = new MasterDetailPageSetup();
GetSetJsonData getSetJsonData = new GetSetJsonData();
Test test = new Test();
public LoginPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
//Implement: return true of false when login is successful or not
if (Email.Text == null && Password.Text == null)
{
if (getSetJsonData.MakeConnection(Email.Text, Password.Text) == true)
{
//getSetJsonData.Test();
test.Help();
//var test = getSetJsonData.sessionString;
//masterDetail.SetupMasterDetailPage();
}
When I call MakeConnection from the LoginPage I get data in the GetSetJsonData class, no problem at all. Now when I call the Test() or the sessionString from the LoginPage it still works, BUT when I try to call this from any other class it for some reason only shows null values, even though I did save them. I just can't seem to make it work and I kinda gave up hope, anything to do this right?
You are creating the GetSetJsonData class as a new instance in LoginPage and also other Page. In this case, the GetSetJsonData class and also sessionString inside the class will only available inside LoginPage.
If you want to make the sessionString available for all places, you can have few options:
Make GetSetJsonData class as static class public static class GetSetJsonData
Make GetSetJsonData class as a Singleton class. Refer to HERE for more details
public class Singleton
{
private static Singleton instance;
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
Put GetSetJsonData instance as a public property in other static class or singleton class. For example: in App class.
public partial class App : Application
{
public GetSetJsonData GetSetJsonDataInstance { get; private set; }
public App()
{
InitializeComponent();
GetSetJsonDataInstance = new GetSetJsonData();
}
...
}
// Then you can access to the instance using:
((App)Application.Current).GetSetJsonDataInstance

programmatically change a dependency in Castle Windsor

I have a class that calls out to an internet service to get some data:
public class MarketingService
{
private IDataProvider _provider;
public MarketingService(IDataProvider provider)
{
_provider = provider;
}
public string GetData(int id)
{
return _provider.Get(id);
}
}
Currently I have two providers: HttpDataProvider and FileDataProvider. Normally I will wire up to the HttpDataProvider but if the external web service fails, I'd like to change the system to bind to the FileDataProvider . Something like:
public string GetData(int id)
{
string result = "";
try
{
result = GetData(id); // call to HttpDataProvider
}
catch (Exception)
{
// change the Windsor binding so that all future calls go automatically to the
// FileDataProvier
// And while I'm at it, retry against the FileDataProvider
}
return result;
}
So when this has been executed all future instances of MarketingService will automatically be wired up to the FileDataProvider. How to change a Windsor binding on the fly?
One solution would be using selector
public class ForcedImplementationSelector<TService> : IHandlerSelector
{
private static Dictionary<Type, Type> _forcedImplementation = new Dictionary<Type, Type>();
public static void ForceTo<T>() where T: TService
{
_forcedImplementation[typeof(TService)] = typeof(T);
}
public static void ClearForce()
{
_forcedImplementation[typeof(TService)] = null;
}
public bool HasOpinionAbout(string key, Type service)
{
return service == typeof (TService);
}
public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
{
var tService = typeof(TService);
if (_forcedImplementation.ContainsKey(tService) && _forcedImplementation[tService] != null)
{
return handlers.FirstOrDefault(handler => handler.ComponentModel.Implementation == _forcedImplementation[tService]);
}
// return default
return handlers[0];
}
}
Test and usage
[TestFixture]
public class Test
{
[Test]
public void ForceImplementation()
{
var container = new WindsorContainer();
container.Register(Component.For<IFoo>().ImplementedBy<Foo>());
container.Register(Component.For<IFoo>().ImplementedBy<Bar>());
container.Kernel.AddHandlerSelector(new ForcedImplementationSelector<IFoo>());
var i = container.Resolve<IFoo>();
Assert.AreEqual(typeof(Foo), i.GetType());
ForcedImplementationSelector<IFoo>.ForceTo<Bar>();
i = container.Resolve<IFoo>();
Assert.AreEqual(typeof(Bar), i.GetType());
ForcedImplementationSelector<IFoo>.ClearForce();
i = container.Resolve<IFoo>();
Assert.AreEqual(typeof(Foo), i.GetType());
}
}
Alternatively you could create a proxy:
public class AutoSelectingDataProvider : IDataProvider
{
public AutoSelectingDataPovider(HttpDataProvider httpDataProvider, FallBackDataProvider fallBackProvider)
{
_httpDataProvider = httpDataProvider;
_fallBackDataProvider = fallBackDataProvider;
}
public string GetData(int id)
{
try
{
return _httpDataProvider.GetData(id);
}
catch (Exception)
{
return _fallBackDataProvider.GetData(id);
}
return result;
}
}
container.Register(
Component.For<HttpDataProvider>(),
Component.For<FallBackDataProvider>(),
Component.For<IDataProvider>().ImplementedBy<FallBackDataProvider>());
This will always first try to get data from the HttpDataProvider if not succesfull use the fallback. If you want you can introduce state and after a failure always use the fallback. This way you can keep using the IDataProvider in your application without needing to obtain a new one from the container.

Categories