0
votes

I am new to simple injector. I have data access layer that has dependency on Force Client. I have register the ForceClient dependency. I want to replace the default value of ForceClient once user login into the application.

Please let me know, how i can change the default values at run time.

Ioc.ServiceContainer.Register(() => new ForceClient(
    "test",
    "test",
    "test"));

Here is the complete detail about the requirement. I have DAL in our Xamarin project that retrieve data from sales force using Developerforce.Force apis. I am writing unit test cases using MOQ to test the DAL.

DAL Code.

public CustomerRepository(IForceClient client)
{
    _client = client;                       
}

public async Task<long> GetTotalContacts()
{
    string totalContactCountQry = "some query"

    var customerCount =  await _client.QueryAsync<ContactsTotal>(totalContactCountQry);
    var firstOrDefault = customerCount.Records.FirstOrDefault();

    return firstOrDefault != null ? firstOrDefault.Total : 0;
}

Unit Test Case Code.

[SetUp]
public void Init()
{
    forceClientMock = new Mock<IForceClient>();
    forceClientMock.Setup(x => x.ForceClient(It.IsAny<string>(), 
        It.IsAny<string>(), It.IsAny<string>(), It.IsAny<HttpClient>()))
        .Return(new ForceClient(It.IsAny<string>(), It.IsAny<string>(), 
            It.IsAny<string>(), It.IsAny<HttpClient>()));              
    forceClientMock.Setup(x => x.QueryAsync<ContactsTotal>(It.IsAny<string>()))
        .ReturnsAsync(new QueryResult<ContactsTotal>());
    forceClientMock.Setup(x => x.QueryAsync<ContactsTotal>(It.IsAny<string>()))
        .ReturnsAsync(new QueryResult<ContactsTotal>() { Records=new List<ContactsTotal>() });            
}

[Test]
public void GetTotalContacts()
{              
    ICustomerRepository customerRepostory = new CustomerRepository(forceClientMock.Object);
    Assert.AreEqual(customerRepostory.GetTotalContacts().Result,0);
}

Simple Injector Registry on application initialization

container.Register<IForceClient>((() => new ForceClient(
    UserState.Current.ApiBaseUrl,
    UserState.Current.AuthToken.AccessToken,
    UserState.Current.ApiVersion)), Lifestyle.Transient);

The instance of ForceClient that i am creating during the registry is being created with all default valued of UserState. The actual value gets assigned once user login into the application.

I except ForceClient instance to have the updated value after login to access the sales force to retrieve the data but the program is giving error on below line DAL

var customerCount =  await _client.QueryAsync<ContactsTotal>(totalContactCountQry);

The reason is that the forceClient still contain default values. How can i make sure that the FoceClient instance get created after login to use the actual value of UserState

1
I'm not sure I understand what you are tryin to do and what your problem is. Your delegate registration already allows the ForceClient to be 'replaced' , since a new instance is injected for every resolve (transient). - Steven
I have tried this with container.Register<IForceClient>((() => new ForceClient( UserState.Current.ApiBaseUrl, UserState.Current.AuthToken.AccessToken, UserState.Current.ApiVersion)), Lifestyle.Transient); - Rajalbar
It does not update the ForceClient instance at runtime. I am registering the dependency on application intialization. On application intialization the UserState.Current object has default values and those values get replaces with actual user login detail once user login into the application. - Rajalbar
I am using ForceClient in DAL to retrieve the data from sales force and the instance require ForceClient to intialze with the logged in user UserState.Current.AuthToken.AccessToken. I see that once the object is created. It does not update later. - Rajalbar
Prevent injecting runtime data into your components; this only leads to trouble - Steven

1 Answers

2
votes

You can accomplish what you want by using Func<T>.

Rather than IForceClient in your classe, you can inject a Func<IForceClient> :

public CustomerRepository(Func<IForceClient> clientFunc)
{
    _clientFunc = clientFunc;
}

public async Task<long> GetTotalContacts()
{
    string totalContactCountQry = "some query"

    // calling _clientFunc() will provide you a new instance of IForceClient
    var customerCount =  await _clientFunc().QueryAsync<ContactsTotal>(totalContactCountQry);
    var firstOrDefault = customerCount.Records.FirstOrDefault();

    return firstOrDefault != null ? firstOrDefault.Total : 0;
}

The simple injector registration:

// Your function
Func<IForceClient> fonceClientFunc = () => new ForceClient(
    UserState.Current.ApiBaseUrl,
    UserState.Current.AuthToken.AccessToken,
    UserState.Current.ApiVersion);

// the registration
container.Register<Func<IForceClient>>( () => fonceClientFunc, Lifestyle.Transient);