8 ms·
If you don't want to write any unit tests, for which there are a myriad of reasons not to, whether you're prototyping, throwing together a small once and done f
by mattmanser 6y ago
If you don't want to write any unit tests, for which there are a myriad of reasons not to, whether you're prototyping, throwing together a small once and done for a client, etc.
Then it's just a massive waste of time and gets in the way.
I really feel that you (and Microsoft) have completely lost sight of the reason why DI was ever even necessary and have become blind to just how much extra code it generates. The only reason was to inject mocks, and people hand-wrung for ages over it because the code to do so infects all the other code. Then people started to try and back justify it with IoC, but it's never really been a convincing argument.
It's also something that if you're not working regularly with it can be very mysterious and when it fails, fails at run-time, quite inscrutably sometimes.
From my perspective it's just boilerplate magic that if you actually need it, fair enough, but if you don't is a persistent, nagging, pain in the ass.
- RobCrusoe 6y ago> If you don't want to write any unit tests, for which there are a myriad of reasons not to, whether you're prototyping, throwing together a small once and done for a client, etc. Then it's just a massive waste of time and gets in the way. A massive waste of time? Adding a constructor and one line to startup.cs is a massive waste of time? Just how long does it take you? > It's also something that if you're not working regularly with it can be very mysterious and when it fails, fails at run-time, quite inscrutably sometimes. If DI fails it’s usually just because you’ve forgotten to add that one line to the startup.cs, and the error you get will tell you that. Can you give me a concrete example of how DI is inscrutable?
- chunkyfunky 6y ago"The only reason was to inject mocks". Must disagree...the reason for DI is to support the Dependency Inversion Principle : "High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g. interfaces)." Won't even go into the host of side-benefits that are gained from adhering to the DIP. In C# the idiomatic way to achieve this is via constructor injection, which is made much easier to manage in ASP.Net with a DI library that works with the framework for you (either the built in one or AutoFac / SimpleInjector, etc.). But you don't have to use a library; many times I'm writing a simple-ish console app and just use good old "Poor Man's DI" where I manually construct my object graphs at startup.
- AndrewSChapman 6y agoI'm not even a C# coder and I can't understand the complaints about this. If you want to code fast and fancy free, use Python or PHP. If you want to use enterprise patterns that will make your code clean, testable and nicely modular, then go for something like C# or Java. Why even use C# if you can't be bothered with DI because... too many lines? mindblown
- mattmanser 6y agoSimply because not only does it not have to be like that, for years we weren't forced to use this stuff if we didn't want to. I like C#, no, I adore C#. I have a bad memory for even the simplest method calls and the sheer power the intellisense in a statically typed language gives me to just not care means I can just code with joy. My personal view on it has always been that someone in MS wrote MVC 1 in response to Rails on the sly. It was fantastic, a breath of fresh air into the MS constant misunderstanding of the web. Especially compared to webforms. For a while, everything was good. Then somehow 7 or 8 years ago the ASP.Net team got obsessed with ramming "best practices" down our throat and everything's gone a bit downhill from there.
- taco_emoji 6y agoYou still are not forced to use it. The documentation will heavily emphasize it, but you can still manually new things up to your heart's content if you want.
- moron4hire 6y agoThis isn't even about C# at all, actually. This is about the web application framework ASP.NET Core. And they don't even have a point in this regard, because nothing is forcing you to use the DI. You wanna make a database connection with ADO.NET and a static connection string in your Controller? Go ahead. You can do that. It's no more effort than it ever was. You want to grow your app to run it in multiple environments and be confident you don't clobber your configuration during migrations? Use ASP.NET Core's DI. Every app framework has some "magic convention over configuration". I personally think ASP.NET Core's "magic" is a lot less pervasive than in, say Django, or RoR. When I was first learning ASP.NET Core--coming from WebForms--there was a learning curve. You don't just throw everything into a Web.config XML bag of doom anymore, with a single, static configuration reading tool that reads just that one file. That particular magic has changed. I mean, if you want to do that, you can, just read the file yourself. But it's not wired up by default anymore. And the new way of doing things was easily learned with a couple of afternoons of reading the documentation. Which you can do, because there is actually documentation, and a lot of it. I think part of the problem might be that people are used to other web app frameworks where the documentation is pretty lacking, so they don't even think to go looking for documentation on ASP.NET Core and think they can just jump in and figure it out. I don't think you could do that going from Django to RoR or vice versa, but people complain when they can't go from ASP.NET WebForms to ASP.NET Core without learning new ways of doing things. Don't like ASP.NET Core? You don't even have to use it. You can (rather easily) write your own web app framework. I've done it in the past, and there are FOSS projects for doing it (https://suave.io/ https://suave.io/, https://www.abp.io/ https://www.abp.io/, https://giraffe.wiki/ https://giraffe.wiki/, https://dotnetify.net/ https://dotnetify.net/, https://www.dotvvm.com/ https://www.dotvvm.com/, https://coalesce.intellitect.com/ https://coalesce.intellitect.com/).
- ThrowawayR2 6y agoNot having used .NET recently, is what they've implemented something like Spring? The description of DI everywhere and inscrutable failures at run-time remind me of that.
- chunkyfunky 6y agoNot sure how Spring does it, but for example in ASP.Net Core, it's really simple. In the app startup class there is a method that's automatically called by the framework whereby it supplies a services container. In this method you "wire up" your interface->concrete mappings public void ConfigureServices(IServiceCollection services) { services.AddScoped<IMyDependency, MyDependency>(); } Later on when for e.g. an APIController is instantiated, once you've declare a constructor dependency on IMyDependency, it gets resolved for you automatically and whatever concrete class is mapped to gets created and passed to the constructor. Outside of ASP.Net (console app for example) you can either do this manually, or you can get a ServiceCollection object from the framework, or you ca nuse a 3rd party DI library, etc. Generally speaking if you don't configure this correctly you get a pretty simple message telling you that the container could not service the request for an IMyDependency or whatever and then it's pretty simple to figure out what you missed in the wire-up.
- bebop 6y agoIf you understand Spring then Asp.net Core will feel right at home. I think .Net tends to be more explicit in the configuration, with DI being no exception. For instance, in Spring you can just annotate a service with @Service and the DI framework will pick that up. In Asp.net Core, you actually have to say IThing is backed by Thing as a singleton when running the application and TestThing when running tests. Edit: Also as others have noted, constructor injection is the way to do DI.
- elboru 6y agoHonest question, what does stop you from simply not using DI in .NET?
- shireboy 6y agoThis was going to be my question. For your own classes and services, nothing is stopping you. You can new up classes without DI all day long. ASP.NET does layer on it's things using DI, but it's boilerplate built into templates. For example, OOB you may use the built in UserManager to authenticate users and store their info in a db. If you want to customize that and NOT use the built-in, you may have 10-20 lines to write in Startup.cs to inject a different UserManager or configure the built-in one differently. I've never felt it was massive or wasted my time vs Node/express work I've done.
- mandeepj 6y ago“ what does stop you from simply not using DI in .NET?” Duh! Then how’d you wire up interfaces with implementation aka constructor injection?
- acupofnope 6y agoLike so: `ISomething something = new Something();` Construction injection is a type of DI, and it's optional, you don't have to use it. edit: for clarity
- mandeepj 6y agoOMG! I was wondering you might be proposing this. You should not be using "new" keyword anywhere in your code. If you have hard coded implementations like that in your code then how will you mock them in unit tests? I hope you'll not reply-with saying "don't write unit tests".
- Thiez 6y agoI am a big fan of DI, but you can often get a lot of useful unit testing done when you try and keep I/O mostly seperate from the rest of the code. If you have ever programmed in Haskell you will know what I mean.
- zzbzq 6y agoUnit tests don't do anything to validate the existence of DI. Most people don't even use DI in their tests. DI is just spaghetti code. The main thing holding C# back is the culture around the DI and weird hostbuilder code associated with ASPNET. If you just skip that part, it's great. Unfortunately a lot of web examples, solutions, and code libraries themselves are ASPNET-focused, and more and more of the code becomes some truly bizarre, unreadable framework injection in an inside-out fluent builder.
- deleted 6y ago[deleted]
- legulere 6y agoDo you mean DI (dependencies being added through the constructor abstracted by an interface) or DI Containers (magic code that magically creates objects for you)?
- manigandham 6y agoWhat exactly is the issue with DI? How else are you going to pass dependencies? How are the errors "inscrutable" when they tell you the exact type that it can't load? Do you just want to `new SomeClass()` instead? If so, what's stopping you from just doing that?
- shireboy 6y agoI really am trying to understand this better. Can you give me an example with some concrete type names where it's massive waste and in the way? When I think DI, I think: //Startup.cs has all the config "goo" I don't want to repeat elsewhere. services.AddDbContext<MyDbContext>(o=>o.UseSqlServer(config.GetConnectionString("foo")); services.AddTransient<MyService>(); //MyController.cs (or Page, etc) and others get to use it with no ceremony: public MyController(MyService foo){ this.foo = foo; } vs no DI, where the config "goo" has to be repeated in every place I intend to use it (or in this case it could also be buried in MyService.cs): public MyController(){this.foo = new MyService(new MyDbContext(ConfigurationManager.GetConnectionString("foo")));} public Dispose(){this.foo.Dispose();} If I knew MyService would never be swapped out and only ever used in one place, I may opt for the no-DI route. I'll often start there then move it to DI when I want testability, reuse of config, plugability, etc..
- DougWebb 6y agoThe way to manage this without DI would be a static method someplace (Startup.cs or elsewhere) which creates the new MyService, stores it, and returns a reference. Then any controllers or pages that need the reference call the static method. The method could return a MyService, or an IMyService if you want to be more flexible. It can always create a fresh object, manage and return a singleton object, or manage a pool of objects. For the new and pool cases, you can have another static method for 'returning' the object when the controller/page is done with it, so you can manage disposal or pool availability. The biggest advantage I see to this approach is in debugging: there is a clear stack trace back to the source of the object, and also to its implementation if you're not using an interface. With DI you often can't tell where an object came from, and sometimes it takes some digging to even find out its exact type (unless you only have one implementation of each interface, which is often the case.)
- ivanche 6y agoThis is well known Service Locator anti-pattern. Described in many places, maybe this one is the most famous https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Patt...
- balfirevic 6y ago> Then it's just a massive waste of time and gets in the way. I find it very useful for several purposes that have nothing to do with mocking or testing. > and have become blind to just how much extra code it generates It doesn’t generate any extra code at all. For the record, I think that built-in .NET DI is pretty bad. It would be better if they managed to avoid including that abstraction in the framework, even if I personally choose to use DI in most of my projects.
- aloner 6y agoWhat DI library do you use instead?
- balfirevic 6y agoDryIoc whenever it’s up to me to choose one: https://github.com/dadhi/DryIoc https://github.com/dadhi/DryIoc I’ve also used Autofac in projects where it was already in place - I don’t hate it but I like DryIoc better.
- codebolt 6y agoForget mocking, the major benefit of DI for me has always been proxies. For our multi-tiered system, this means managing caching and logging of certain calls and events at the level of data access. And at the service level, it means dealing with things like authorisation. Smart use of DI sets the system up in a way were it's easy to handle these types of cross-cutting concerns where appropriate, and with minimal boilerplate. It also simplifies refactoring.