I have more like desing question as I'm refactoring quite big piece of code that I took over.
It's not modular, basically it's pseudo-object-oriented code. It contains hard coded dependencies, no interfaces, multiple responsibilities etc. Just mayhem.
Among others it contains a great deal of internal calls to class called Audit, that contains methods like Log, Info, LogError etc... That class has to be configured in application config in order to work, otherwise it's crash. And that's the main pain for me. And please, let's focus on that issue in responses, namely making client code independent of logging classes/solutions/frameworks.
And now, I would like those classes, that have that Audit class dependency hardcoded, refactored in order to obtain several benefits:
First is to extract them nicely to different assemblies, as I will need some functionality available in other applications (for instance generating attachments code - let's call it AttachmentsGenerator class, that until now was specyfic to one application, but now that code could be used in many places)
Remove internal dependencies so that other application that will take advantage of my AttachmentsGenerator class without the need to add reference to other
Do a magic trick in order to allow AttachmentsGenerator class to report some audit info, traces etc. But I don't want it to have hardcoded implementation. As a matter of fact, I don't want it to be mandatory, so it would be possible to use AttachmentsGenerator without that internal logging configured and without the necessity for the client code to add reference to another assemblies in order to use logging. Bottom line: if client code wants to use AttachmentsGenerator, it adds reference to assembly that contains that class, then it uses new operator and that's all.
What kind approach can I use in terms of design patterns etc to achieve it? I would appreciate some links to articles that address that issue - as it can be timeconsuming to elaborate ideas in answer. Or if you can suggest simple interface/class/assembly sketch.
Thanks a lot,
Paweł
Edit 1: As my question is not quite clear, I'll rephrase it once again: This is my plan, are there other interesting ways to do this?
Seems like the easiest way to do this would be to use dependency injection.
Create a generic ILogger interface with methods for logging.
Create a concrete implementation of ILogger that just does nothing for all the methods (e.g. NullLogger)
Create another concrete implementation that actually does logging via whatever framework you choose (e.g. log4net)
Use a DI tool (spring, structure map, etc.) to inject the appropriate implementation depending on whether or not you want logging enabled.
Implement logging (and any other cross-cutting concerns) as a Decorator. That's way more SOLID than having to inject some ILogger interface into each and every service (which would violate both the Single Responsibility Principle and DRY).
Related
I have the following structure:
PdfGenerationService (umbrella)
PdfGenerationDataService (gets data for umbrella)
PdfGenerationFunctionService (calls Azure function "microservice" to gen PDF)
PdfAzureSaveService (saves PDF to storage)
The problem is that other devs and myself have the tendency to try to use one of the "supporting" services outside of the "umbrella" service, when they really have no stand-alone functionality. We remember this too late, and by the time we do, we need to refactor.
e.g. we call the supporting PdfAzureSaveService from a controller, and then remember that we have the PdfGenerationService that does all of this for us without getting into the details and need to refactor.
I want to limit the helper services to only be usable within the umbrella PdfGenerationService. Access levels don't seem to help me with that, unless I want to make an arbitrary parent class that all 4 inherit from and then make the helper services protected. The other alternative is to put all the helpers into private methods on the "umbrella" service, that really violates DRY imo.
tl;dr: Is there some way to mark methods as only accessible from one service?
edit: JHBonarius made a good point that I should mention - these services ARE exposed via standard .NET Core DI. There is no real reason that they couldn't be static (and avoiding DI entirely), but that seems to still leave the problem of other services/controllers just importing the namespace and using the static services where they shouldn't.
So your scenario is that you have a class which requires three other classes:
public PdfGenerationService(
PdfGenerationDataService s1,
PdfGenerationFunctionService s2,
PdfAzureSaveService s3
)
And you register those classes with DI:
services.AddTransient<PdfGenerationService>();
services.AddTransient<PdfGenerationDataService>();
services.AddTransient<PdfGenerationFunctionService>();
services.AddTransient<PdfAzureSaveService>();
And now you want to prevent developers from writing, in their own code:
public Foo(PdfGenerationFunctionService s1)
Because they're supposed to use PdfGenerationService as a dependency?
Then move all those classes into their own library, and make the three dependencies of the first service internal. Now other code can't refer to them by their name, so it can't ask for them to be injected.
Or write an analyzer that checks that other code doesn't use those classes. Or mark them obsolete, suppressing the warning in PdfGenerationService's constructor. Or throw an exception in the three other class's methods if the method one stack frame lower doesn't originate from PdfGenerationService (but don't).
I've just started learning about IoC, and I understand the general use of it, but so far, the loading process from AutoFac, Ninject and Zenject seem to be based on loading an object not based on data.
In other words, ConsoleLogger is created when ILogger is requested, which does not require any special ID's, and that makes sense. However, what about when I want to load IUser for Id 4? Is there a standard IoC for handling that, or are the interfaces supposed to carry methods for loading based on Id?
For instance, am I supposed to have IUserManager, with LoadUser(int id) as a method? or is there some IoC structure for this as well?
Thanks.
[note: I did search the web for this, but my queries did not seem to pull up relevant information and the similar question search yields too many generic questions to filter]
IoC containers rules the way we link object's by dependencies, dependencies means some logic under Iterfaces, so IoC mostly works on Type level rather then Instance level.
Please note that types which has no any dependencies, interfaces as well as special scope requirements may be legally created by using "new" keyword for e.g. Data Transfer Objects (dto's).
In your case, you probably need a some kind of factory that can realize by parameters what kind of object caller is needed.
However, I'll suggest to you separate data from business logic as much is it can be separated.
public List<IBusinessObject> RetrieveAllBusinessObjects()
{
var businessObjectType= typeof(IBusinessObject);
List<Type> implementationsOfBusinessObject = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(businessObjectType.IsAssignableFrom).ToList();
return implementationsOfBusinessObject.Select(t =>(IBusinessObject)Activator.CreateInstance(t)).ToList();
}
I was suggested by a user on stack overflow that I should check out dependency injection as a workaround for the above snippit. What would be the benefits of this?
Just a little overview on what the scenario is:
Our database has little to no store procedures so we have begun implementing C# business objects for our more complicated tables. As we are hoping to switch databases some time soon this seems to be the best option. All of the business objects must be loaded using reflection at runtime to help manage them. All of these business objects implement the interface IBusinessObject.
The suggestion to use dependency injection came from this question
EDIT:
The RetrieveAllBusinessObjects method is in a class behind an interface so is directly testable
We use AutoFac if that changes anything. We don't use a separate config file.
-
instead of using the code above, you simply use DI which is configured in the config file of the app but also sometimes you can decorate a property or a parameter in a method which will then be automatically injected in (by the mapping set up either programmatically or via config) when the request is made to access that object or when it is going to be invoked in the method being called in the params.
it also makes it a bit more testable in that you can create different concrete types which implement of an interface, then instead of having to recompile the code, you just flick the mappings by the config file and viola...all works.
DI would do the above without you having to write code to do it so there's less opportunity for you to introduce bugs.
DI gives you many more benefits such as
Making it easier to test individual units of code. Dependencies can be mocked, so you can limit the code being tested
Easy to understand the dependencies within your code. Dependencies generally get injected in certain places, usually the constructor.
Linked to 1/ above, because you should now defined interfaces between your code, when your requirements change & you need to rewrite a component, you can do so with a higher level confidence that it will work with your existing code-base.
There are other benefits that others can probably describe better, but you'll need to evaluate those according to your needs.
We are working on two product lines that will share the same code.
For functionality that differs, I have both product lines implement the same interface (or base classes in some case) and these types will be created in the Main class (which is separate for both product lines) and passed further downstream.
For code that is deep inside the business logic, it is very hard to have product line specific code. We do not want to user if(ProductLine == "ProductLine1") and else methodology.
So I am planning to implement a Factory class which will have static methods to return NewObject1(), NewObject2() and so on. This Factory class will be registered in the Main class as Factory.RegisterClient(ProductLine1).
So with the above approach, the factory(which internally contains ProductLine1Factor & ProductLine2Factory) knows which type of objects to create.
Do you know a better approach to this problem. Please note that ProductLine1 was already existing and ProductLine2 is something new (but is 90% similar to ProductLine1). We cannot do drastic refactoring such that both product lines exist. We want to do as minimally invasive code changes as possible.
The factory approach typically exposes an interface, but the problem with interfaces is that I cannot expose static types which are also needed.
I would really appreciate if some experts would shed some light.
Your approach sounds fine.
Instead of a custom crafted factory, why don't you use a fully fledged IoC framework like NInject or Unity? You could have the service implemented twice, for each client, and select one in a container configuration file, statically. This way you don't even need to change the single line of your code if you add yet another implementation, you just reconfigure i.e. make some changes in the xml file.
Anyway, an IoC container is just a tool, use it or not, it just replaces your factory (IoC containers are sometimes called "factories on steroids").
We have a project with separated bussiness layer. It's like lots of services (classes) in separated project in the solution. Also we use ninject to manage dependancies.
All classes in bussiness layes project are internal, and it communicates with «another world» through interfaces.
If to create new project that would contain test then it wont see internal classes (but yeah we can do a hack and declare Internal to Public in AsseblyInfo).
What i really need to know is what's neccessary to test:
We can create test envirement of everything, and test only through produced interfaces (there is no «clear» DAL, we are using linq2sql, but its possible to be mocked)
This way looks goods, because we know nothing about internal BisLayer structure and test only «contract» functionality. But the bad side is that the system has lots of options, settings and bindings and it seems impossible or pretty hard to check all possible variants of it
We can place tests in the same project or set attribute to make internal being seen as public, so we'd be able to test internal classes. Its good because we can test almost everything, but its hard to control bindings, cos it'd be nice Ninject to do it, and we would only override bindings we need in concret test.
Also its not clear how to test classes implementing the same interface (and doing similar things). Like we have few implementations of Cache but each impl-tion keeps data in different places (mssql, key-value db, asp cache, etc), so tests for each implementation actually would be the same
As you say you need to have access to the classes in order to test. So, make only the internals that are exposed to the outside trough interfaces accessible from the outside.
Write your tests only against the behaviour that is exposed to the outside, "another world" as you call it.
Write the more generic test cases first and the go into details as needed.
As this will be an ongoing process together with the development/change of the actual functionality you'll the be able to decide how many fine grained scenarios you actually need.
Also take a look at Ninject Mocking Kernel extension https://github.com/ninject/ninject.mockingkernel