I'm having trouble figuring out what the best approach is these days for Ninject and ASP.NET MVC 3.
I have used Install-Package Ninject.MVC3 on my application and have my bootstrap class with the following methods:
public static void Start()
public static void Stop()
private static IKernel CreateKernel()
private static void RegisterServices(IKernel kernel)
It's all great and it loads my modules as expected. But historically what I have done is something like this:
MyApp.dll
Kernel.Bind<ISomething>().To<Something>();
Kernel.Bind<IBlah>().To<Blah>();
Kernel.Bind<IFoo>().To<Foo>();
MyApp.Tests.dll
Here I want to override ONLY ISomething's binding, so I used to just unbind the thing I needed to mock/whatever and rebind:
Kernel.Unbind<ISomething>();
Kernel.Bind<ISomethig>().To<TestSomething>();
But there isn't a method in the Nuget package that implies a thought through way to achieve this with the App_Start class from the original library. If I put another Ninject bootstrap class in my test app it only seems geared up to build a new kernel:
[assembly: WebActivator.PreApplicationStartMethod(typeof(TestNinjectBootstrapper), "Configure")]
I could store the kernel in the original bootstrapper statically and call from the tests project, but this feels wrong. Am I thinking too much and missing something? Or thinking too little :)
Argh. What is a good approach?
To reuse interface/class mapping registration in different project there is ability to create NInject modules. Modules just need to implement the INinjectModule interface, but most should extend the NinjectModule class for simplicity.
So you can place interface/class mapping inside module like in the following example:
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWeapon>().To<Sword>();
Bind<Samurai>().ToSelf().InSingletonScope();
}
}
After you define such module you can instantiate Kernel with mapping defined in this module.
All that you need is to specify this module as argument during creating Kernel object:
IKernel kernel = new StandardKernel(new WarriorModule());
Note that you can create and instantiate kernel with multiple modules.
So, modules will help you to reuse default mapping configuration. Mapping configuration will be defined in one place which will simplify maintance especially if there are several projects which uses the same interface/class mapping configuration.
There are also some other features like 'Dynamic Module Loading' and etc. More information about modules can be found here.
Related
I'm using Mapster for mapping and Simple Injector in my .net framework 4.8 MVC and WebApi controllers.
I'd like to inject Mapster as a dependency in my services but I can't figure it out how to make it work with Simple Injector. The Mapster documentation is really vague in my opinion:
Mapster - Dependency Injection
Mapster - References
Can someone provide and example of how to use Mapster with Simple Injector? Doesn't matter if the controller is mvc or a web api.
The code I need is the configuration in Application_Start in Global.asax.cs and in the service concrete. Thanks!
I'm unfamiliar with Mapster, but after looking at the documentation link you provided, I'm assuming that integrating with Simple Injector can be done as follows:
var config = new TypeAdapterConfig();
container.RegisterInstance(config);
services.RegisterSingleton<IMapper, SimpleInjectorMapper>();
Where SimpleInjectorMapper is:
public sealed class SimpleInjectorMapper : ServiceMapper
{
public SimpleInjectorMapper(
Container container, TypeAdapterConfig config)
: base(container, config)
{
}
}
The 'trick' here is that the Simple Injector Container class implements System.IServiceProvider, which is the base interface used by most of the DI facilities in .NET and .NET Core and is the base interface that the MS.DI abstraction relies on. Mapsters ServiceMapper expects an IServiceProvider in its constructor, which is now provided using the Container.
There are a few downsides to this approach. Main downside is that in case a dependency is missing, you'll get a more generic "no service registered" exception in line with what MS.DI would throw, instead of a very information rich exception that Simple Injector would throw in case the resolve would fail when you call Container.GetInstance.
This, however, is a as far as I can go in providing an answer. If you wish to integrate more deeply with Simple Injector, you likely need a more complex SimpleInjectorMapper implementation, but others (e.g. the designers behind Mapster) need to help you with that. At least, hopefully, this answer will get you started.
I am confused on how to use a Razor Class Library that requires injected objects.
I created a new razor class library project.
There is no program.cs file and hence no WebAssemblyHostBuilder to add services to?
How do I inject dependencies into the components?
A library is simply that. It's not an application. You load the DI objects in the application project. You can write extension classes in your library as a wrapper to load all the necessary objects. builder.Services.AddServerSideBlazor() is just such an extension.
Here's an example extension method for the Weather Forecast.
public static class ServiceCollectionExtensions
{
public static void AddWeatherServices(this IServiceCollection services)
{
services.AddSingleton<WeatherForecastService>();
}
}
And use it in the application startup:
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddWeatherServices();
You inject the services into your components as normal. If you use a component in an application and the necessary services aren't loaded the page on which the component is being used will throw an error.
I am using Xamarin Forms. I would like to download jpg file (it is done) and then open that jpg in default application on Android/iOS (opening photo browser with this photo). Of course photo is single example, I would like to open any file in default application.
I found several solutions native-only but my application is designed to be cross-platform. I though that I can use Launcher from Xamarin.Essentials package but apparently I can't.
How to achieve this?
You can have a try with Xamarin.Essentials: Launcher:
var fn = "File.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(file)
});
I found several solutions native-only
Opening something in another app is quite close to the system for a mobile application and there are some things to consider, which dependend on the platform. Usually, mobile apps run in a sandbox with very limited access to the surrounding system. Particularly this means that, if you downloaded a file to the sandbox of your app, other apps (which native viewers are), aren't allowed to access the file.
On Android, you can copy the file to a shared space (see Application.Context.GetExternalFilesDir(null)) and then open it. This might be possible with Essentials, but I'm not quite sure, but since we're on the Android platform anyway now, you could create an intent now anyway.
On iOS you create controllers from within your app (for example the QLPreviewController to preview the file) that may access items in your sandbox. Depending on the type of controller (e.g. UIActivityViewController) they may open other apps.
How to use this platform-independently?
Since you are programming a platform independent app, you'll have to take care that the correct class is called to the platform dependent work. There are several options how you can achieve this
Use the DependencyService
Use a real dependency injection framework
Use an abstract base class with initialization in the platform dependent projects
DependencyService
To use the Xamarin.Forms DependencyService you need two things
An interface for the functionality you'd like to implement
One implementation per platform
Assuming you hvae a simple interface to share a file
public IShareFile
{
void ShareFile(string fileName);
}
you can implement an implementation of this interface on each platform and add the DependencyAttribute to the assembly. e.g. for iOS:
[assembly: Dependency(typeof(MyApp.iOS.DeviceOrientationService))]
namespace MyApp.iOS
{
public class ShareFile : IShareFile
{
public void Share(string fileName)
{
// implementation goes here
}
}
}
The general scaffold is the same for Android, albeit the implementation differs.
Using a real dependency injection framework
Basically it's pretty much the same. You can skip the DependencyAttribute, though. In order to make the implementation available you'll have to get hold of the DI container from your platform specific code, which might be tricky. This might be an overshoot for a single dependency, but if you're using a DI container anyway and there are X dependencies, it might be worth the effort.
Using an abstract base class
Add an abstract base class to your project
public abstract class ShareFile
{
public static ShareFile Instance { get; protected set; }
public abstract void Share(string fileName);
}
and in your implementation in the platform specific project, you add an Init() method
internal class ShareFileImpl : ShareFile
{
public static void Init()
{
ShareFile.Instance = new ShareFileImpl();
}
public void Share(string fileName)
{
// implementation goes here
}
}
This init method must be called from your platform specific code. Most likely during initialization. The implementation can then be accessed via its abstraction from your platform independent code (of course you'll see only the abstraction, public methods added to ShareFileImpl won't be visible from your platform independent code).
ShareFile.Instance.Share(fileName);
A combination of the abstract class approach and dependency injection is also conceivable. When registering your classes in the DI framework, you could register the platform instance like
container.RegisterInstance<ShareFile>(ShareFile.Instance);
This way you can make use of the DI container features (e.g. constructor injection), while keeping the hassles of using the DI container from your platform specific project away from you. The drawback is, that you'll still have to call ShareFileImpl.Init() from your platform specfic code.
I have a ASP.NET web application (not MVC) which is actually a CMS application. I'm trying to set up StructureMap IoC framework and it's working well, but I've now hit a blocker in my understanding.
In my understanding, StructureMap enforces a pattern where all dependencies are registered in the core application assembly, so underlying assemblies do not themselves have a dependency on StructureMap.
So, say my application is My.App and it references another assembly My.Logic. My dependencies are all registered in a Container in My.App. This means that a class in My.Logic can take injected dependencies using a constructor like this:
public class Foo
{
private readonly IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}
But now I have a case where my class in My.Logic is a type which must be registered in the CMS, and this requires that it has an empty constructor.
So the problem is, if I can't inject using constructor parameters, and My.Logic doesn't have a dependency on My.App so I don't have access to the IoC container, is it possible to use StructureMap to handle this scenario?
If not, what alternative do I have other than create the class within the same assembly as the IoC container?
Use setter injection. See here
For<IBar>().Use<MyBar>();
Policies.FillAllPropertiesOfType<IBar>();
Whenever I try to actually unit test a presenter and a mocked view, I end up running into too many database dependencies
public EditAccount(IAccountEditPage _view, ISession _session, IResponse _response)
{
}
public void view_SaveUser()
{
//Class that takes the view's data and persists it to DB
}
Obviously I can't write unit tests for this presenter because I have a concretion of using my model class that has a strong database dependency.
How am I supposed to removed the dependency on the database without constructor injecting every class that touches the database in my presenter? I don't want to do this every time in every view I have.
I'm using moq, if it helps.
Edit : Also I should mention that the code in "view_SaveUser" is very lean and isn't direct database access or anything like that. It's usually only a few lines. I'm not overstepping the scope of the presenter, AFAIK.
If you don't want to inject the instances on the constructor another option you have is using a setter injection using a IoC framework as Spring.Net or Castle Windsor to inject the dependencies.
Doing this, you would only need to specify on the framework configuration which classes are used for real code and for test project, dependencies would be automatically injected and you would avoid having to use the contructor.