5

I've got a Prism application with DryIoc as container. I'd like IHttpClientFactory to provide HttpClients to my typed clients, which are like this:

public class ExampleService : IExampleService
{
    private readonly HttpClient _httpClient;

    public RepoService(HttpClient client)
    {
        _httpClient = client;
    }

    public async Task<IEnumerable<string>> GetExamplesAsync()
    {
        // Code deleted for brevity.
    }
}

In App.xaml.cs I register my typed client so they can be injected in viewmodels with the following:

public partial class App

// ...

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    // Code deleted for brevity.
    containerRegistry.Register<IExampleService, ExampleService>();
}

And that's before trying to use IHttpClientFactory.

Now, to add it, we should AddHttpClient() on IServiceCollection. That's where I thought DryIoc.Microsoft.DependencyInjection was needed, so, still in App.xaml.cs, I wrote the following:

public partial class App

// ...

protected override IContainerExtension CreateContainerExtension()
{
    var services = new ServiceCollection();

    services.AddHttpClient<IExampleService, ExampleService>(c =>
    {
        c.BaseAddress = new Uri("https://api.example.com/");
    });

    var container = new Container(CreateContainerRules())
        .WithDependencyInjectionAdapter(services);

    return new DryIocContainerExtension(container);
}

The problem is that in my ExampleService I'm getting client with the following specs:

{
   "DefaultRequestHeaders":[
   ],
   "BaseAddress":null,
   "Timeout":"00:01:40",
   "MaxResponseContentBufferSize":2147483647
}

whilst I expected BaseAddress to be https://api.example.com/, so the REST API call fails.

What is the correct pattern to use IServiceProvider when using Prism for Xamarin.Forms with DryIoc? Unfortunately there's no documentation or open source code available on the following matter, and I am kind of lost.

Thanks you, and have a great day.

UPDATE #1

As per kind Dan S. guidance, DryIoc.Microsoft.DependencyInjection was uninstalled so the project came back at its state before trying to use IServiceCollection dependencies (in my case, IHttpClientFactory), then I installed Prism.Forms.Extended and later Prism.DryIoc.Extensions.
After that CreateContainerExtension() in App.xaml.cs became:

protected override IContainerExtension CreateContainerExtension()
{
    var containerExtension = PrismContainerExtension.Current;
    containerExtension.RegisterServices(s =>
    {
        s.AddHttpClient<IExampleService, ExampleService>(c =>
        {
            c.BaseAddress = new Uri("https://api.example.com/");
        });
    });
    return containerExtension;
}

and containerRegistry.Register<IExampleService, ExampleService>(); was removed from RegisterTypes().

Now ExampleService finally gets its HttpClient injected and everything is working.

UPDATE #2

The only packages related to Prism I am using are Prism.DryIoc.Forms and Prism.DryIoc.Extensions. I completely removed the override of CreateContainerExtension() in App.xaml.cs and refactored RegisterTypes() to

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    // Code deleted for brevity.
    containerRegistry.RegisterServices(s =>
    {
        s.AddHttpClient<IExampleService, ExampleService>(c =>
        {
            c.BaseAddress = new Uri("https://api.example.com/");
        });
    });
}  

This way I get thrown a NotImplementedException.
However, by overriding CreateContainerExtension() with the following:

protected override IContainerExtension CreateContainerExtension() => PrismContainerExtension.Current;  

Everything is finally back to working!

Oliver
  • 926
  • 2
  • 12
  • 31

2 Answers2

7

If you want to use IServiceCollection extensions such as AddHttpClient I would suggest that you use the Prism Container Extensions. In your case it would be Prism.DryIoc.Extensions. The Container Extensions provide a lot of additional support including support for registering services with via the Service Collection extensions.

You can either install Prism.Forms.Extended and it will all just work, or you can update your App as follows:

protected override IContainerExtension CreateContainerExtension() =>
    PrismContainerExtension.Current;
Dan Siegel
  • 5,724
  • 2
  • 14
  • 28
  • Thank you for your time Dan, and sorry if I may sound like a newbie, I started getting my hands on Xamarin.Forms two weeks ago and I'm still practicing and learning. Okay so based on your suggestion, the best way to use `IServiceCollection` dependencies with Prism for Xamarin.Form and DryIoc as IoC container would be to upgrade from the default **Prism.DryIoc.Forms** to **Prism.DryIoc.Forms.Extended**, did I understand correctly? I uninstalled the former, cleaned up the solution and installed the latter, but couldn't find an overriding method with `IServiceCollection` as parameter. – Oliver Feb 06 '20 at 00:29
  • 2
    To be very clear you will not use Prism.DryIoc.Forms.Extended as it has been deprecated. You need to install Prism.Forms.Extended and the Extensions package for the container you want. It will automatically wire itself up, and you won't need to do anything different than a normal Prism Application. – Dan Siegel Feb 06 '20 at 02:49
  • Hello Dan, I think I managed to get it working. Could you please take a look if the way I solved is the way you recommended or/and if it can be improved or simplified? Thank you. Please scroll down to [UPDATE #1](https://stackoverflow.com/q/60078277/5495385) – Oliver Feb 06 '20 at 09:26
  • 1
    @YanKarin close but get rid of CreateContainerExtension... your registration should be with the ContainerRegistry in the RegisterTypes method along with anything else you're registering. – Dan Siegel Feb 06 '20 at 15:38
  • I updated the question one more time, could you please take a look at update #2 and check if this is the ultimate pattern, the one you were advising? Thank you. – Oliver Feb 08 '20 at 15:12
  • 1
    You should not be using Prism.DryIoc.Forms with Prism.DryIoc.Extensions. Either keep the code as is with Prism.Forms or stop trying to override CreateContainerExtension and use Prism.Forms.Extended with Prism.DryIoc.Extensions – Dan Siegel Feb 09 '20 at 00:05
  • 1
    If I try to use Prism.Forms and Prism.DryIoc.Extensions, then PrismApplication can't be located because it's not included in the Prism.Forms package. Are you sure I shouldn't be using Prism.DryIoc.Forms? I think it's the only way to have PrismApplication if not wanting to use Prism.Forms.Extended. – Oliver Feb 14 '20 at 08:24
  • 2
    If you are using Prism.Forms rather than Prism.Forms.Extended you would need to inherit from PrismApplicationBase. CreateContainerExtension is the only thing that PrismApplication implements in the container specific package. Since you are using Prism.DryIoc.Extensions you shouldn’t also be referencing Prism.DryIoc.Forms. Hope that clears it up for you. – Dan Siegel Feb 14 '20 at 14:35
0

Adding as this is the only post I've found in weeks of searching that explains how to do this.

I'm using Unity rather than Dryloc but the solution is the same.

Install ONLY these additional packages:

Prism.Forms.Extended

Prism.Unity.Extensions

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    //Omitted Code

    containerRegistry.RegisterServices(serviceCollection =>
    {
        serviceCollection.AddHttpClient<IApiService, ApiService>(client =>
        {
            client.BaseAddress = new Uri("Your Address Here");
        });
    });
}

public ApiService(HttpClient client)
{
    //Do Stuff
}
ledragon
  • 299
  • 6
  • 17