I want to create a class library and publish it to artifactory. However, I have organized my solution such that there is a public "Client" project, then an internal "Domain" project that contains business logic that I do not want to publish.
My issue is that apparently I have to publish the Domain project if the Client project depends on it. If I don't, then when I attempt to install the Client dependency in another project, I get an error stating that Domain cannot be found.
Is it possible to accomplish what I'm looking for, i.e., an entire assembly that is only accessible to another assembly in the same solution? The key point is that I want the classes within Domain to not be accessible to other projects. I know I could put them in the Client assembly and mark the internal, but I prefer the organization of having an entirely separate project, as well as not having to mark every single class internal.
Related
I'm not new to C# programming, but I suppose I'm new to programing "the right way" in C#. I've worked in C on embedded devices for years and have written desktop apps to support them. First in VB6, then in C#.
I recently started making better use of classes for reusing code (and for instantiating more than one instance of the class in a program). For example, I "wrapped" a UART interface with some additional functionality so I can use the same code for multiple ports by creating an instance of the class for each one.
It is in a separate file, but still in the same program namespace, so when I want to reuse it, I have to copy the file and change the namespace to the new project.
I'm sure there's a way to create it such that I can just reference it like everything else with either a "using..." reference at the top of the program or with a "Project | References..." checkbox. But for the life of me I can't find a good learning journey for this.
Any direction would help.
You want to create your reuseable class in an assembly - this is the equivalent of a dll from your C experience.
To create an assembly, have a separate project of type assembly (instead of exe) . You can reference the assembly from other projects. If your project is in the same solution you can reference the project, otherwise you can reference the compiled assembly.
C# uses a packaging system called Nuget, so you can package your assemblies into "Nugets" which you host in a Nuget Server. You can then use tooling to discover and import these.
Please create a Class Library project and include your class into that project. Make sure your class is public. Once you build this project you'll get an assembly which can be referenced from other projects. See Tutorial: Create a .NET class library using Visual Studio
There are different ways of referencing it.
You can have the class library project in the same solution as the main project. In this case you should add a project reference.
You can copy the compiled *.dll file to some folder in your solution (e.g. Lib) and add an assembly reference.
If this assembly is to be used in multiple projects please consider creating a NuGet package with this library and pushing it to some repository. Then other projects can add a package reference to this package.
Details:
How to: Add or remove references by using the Reference Manager
Install and manage packages in Visual Studio using the NuGet Package Manager
It is in a separate file, but still in the same program namespace, so when I want to reuse it, I have to copy the file and change the namespace to the new project.
Well, it isn't the best practice but (unfortunatly) still a common behavior. So don't worry to much about it.
What you could do to improve it place the file (and other reusable parts) in a seperated csproj.
For example name the project of the type class library and name it VinDag.Tools. Within the project create a folder UART and place the wrapper there. The namespace of the wrapper would then be VinDag.Tools.UART.
From know on you can just reference the class library instead of renaming the file. It's not necessarily required to be the same namespace as the project.
From there you can start considering (private) nugets. This would prevent you from copying files/csproj around.
I have a project that requires certain functions, and I have created an interface for these functions. If the implementations of the interface is to be performed by external parties, what should be the correct way to do this?
The idea I have is to create a class library project (MyInterface), define my interface (IModule) in this project, compile this and give the DLL (MyInterface.dll) to the external parties. The external parties would develop/implement using the DLL as a reference, then give me their final DLL. My main project would reference the MyInterface project, as well as all the implementations. In my code, I would do something like this:
IModule module = new ImplementationA();
module.DoSomething();
module = new ImplementationB(); // Change implementation at runtime
Is this approach correct? Are there better alternatives?
Side question: Is this strategy design pattern? Or facade?
I would probably use configuration to load the 3rd party assembly at runtime, look for a single factory type, create a singleton instance, and create each implementation class through the factory. This way you can give all of your assemblies to a 3rd party, and they can build and update their component at any time. They depend on your code, but you don't depend on theirs.
I don't know much about your project or situation, but I would consider publishing a nuget package of your interface and allow the third parties to install it. That gives you the power of versioning when you need to make changes to your interface(s). You publish the change(s) as a new version and then they can update their installed package of your dll accordingly. That at least gives them a concrete way to develop against what you require in a controlled, robust manner.
In case you aren't familiar with nuget packages, in Visual Studio you can right click the necessary project with the dll within the solution and select Pack. You can also change pack settings by going to the Package tab in the project properties (same context menu on the project, select Properties).
You can also do dotnet pack through the command line, which has a lot of command line arguments that you can leverage.
Whichever way you go about it, you can publish your nuget package to nuget.org, to some other service with an artifact feed, or simply to a file on disk.
Helpful Nuget Package References:
Installing a nuget package
Create and publish a nuget package
As for your question about the pattern, typically when you switch implementations like that at run time that is the strategy pattern at work. The facade is when you use a single class to abstract away multiple instances of different sub-system classes. So for example lets say you have operation classes for GetUser, UpdateUser and DeleteUser. Your facade could be a single class called UserManager and within that class you would expose functions of each user operation. Inside those functions you would be accessing each individual instance of each operation class and passing the call on to those functions internally. In this example, inside the facade you know you are working with 3 classes. From the perspective of code/callers outside of it, they only know about the single UserManager class.
I have a question that has been bothering me for awhile. I ran across this problem a few years back when I was dealing with writing a generic logging wrapper around some hosted provider instances using log4net.
The idea was simple enough, I wanted to write a logging and metrics that hid all the implementation in a separate visual studio project so when you wanted to add any telemetry support to another application you could just include the project, new up an instance of the logger and start logging using generic calls. If you ever switched providers or tweak logging settings, it wouldn't require any changes to the host applications.
This creates a strong decoupling point, where the main application used an interface in a logging class library, but would know nothing about the packages or providers that the logging class library was using to do the real work.
When I did this and tried out using Loggly's nuget package and log4net, I found that the calling application had to have a ref to the nuget package or else the dependent assembly would not be copied to the build directory. At the time I just wrote this off as something odd that they Loggly engineers were doing. But I have since encountered the same behavior in some, but not all other packages. (DogstatsD doesn't have a problem, Raygun does, etc..)
I have noticed that some nuget packages in assemblies are automatically copied into the parent output directory, but when I look for the setting that controls this, I cannot find it.
I have written dozens of class libraries over the years, and I have never had a problem with 'chained dependency assemblies (a refs b, b refs c, etc.) resolving when I build. It only seems to be some nuget packages that are a problem.
How do I force nuget packages referenced by a class library project to copy into the build directory without an explicit reference in the application?
Ok, I figured this one out.
This is a problem only for the Log4Net & Loggly wrapper assembly combo in particular because it is referenced entirely at runtime. Log4net loads up its required log appenders at runtime, and because .net doesn't see a ref to the assembly at build time, it assumes that it isn't being used and omits copying the required assembly to the bin directory. The solution when you know this is simple, just write an empty dummy method in the referenced library that you can call in the main application. This will cause .net to include the assembly in the build.
While this problem is specific to the Log4net library, it could occur anywhere that you are using an assembly that is only used with runtime reflection.
I've searched for an answer on google using:
"The type 'Microsoft.SqlServer.Management.Smo.Server' is defined in an assembly that is not referenced."
Why does using Microsoft Sql Server Management Objects (SMO) in the DAL require references to SMO dlls in a referenced project?
using sql smo in referenced projects
sql smo in layered solutions
sql smo reference requirements
and probably a few others and have not found a solution or explanation to this issue.
Admittedly, I'm only a journeyman googler, so if someone wishes to power level me and point the way to an existing resource, I'll gladly go spelunking from there.
Here's my set up:
I've got a layered solution: DAL, Business Logic, Services, UI. There's a hosts project that hosts the services. I'm actually using the VS2010 extension layerguidance.codeplex.com, which is quite nice, to set up all these projects. I'm using SQL Server 2008 Express and SMO v 10. All solution projects are referenced using Project References. All projects compile to a common top level Bin folder.
Now the problem:
Among the classes in the DAL I have an SmoTasks class which handles interfacing with SMO objects and a Utilities class which abstracts from SmoTasks and provides acces to its functions without requiring any SMO objects for parameters, so that referencing projects (read: Business Logic Layer) can interface using non-SMO types. All is well in the DAL, it compiles fine, the methods pass their tests - it feels good about its place in my world. Then in the BLL I have a component which handles using the Utilities class to perform database configuration for the application which will be exposed via the services. The BLL uses a project reference to the DAL and sees the DAL classes (a la intellisense) as expected. When I compile though, I get:
The type 'Microsoft.SqlServer.Management.Smo.Server' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.SqlServer.Smo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91'.
The code in BLL looks like this:
public bool CreateTables(string connectionString)
{
bool result = default(bool);
// Data access component declarations.
Utilities utilities = new Utilities();
// Step 1 - Calling CreateTables on Utilities.
result = utilities.CreateTables(connectionString);
return result;
}
The line the error points to is:
result = utilities.CreateTables(connectionString);
I could, obviously, add the SMO references to the BLL and then the BLL would be happy, but that violates my design goal of loosely coupled projects. If I add the SMO assemblies to the BLL, it compiles and then referencing BLL objects in the services layer doesn't cause a complaint. My question is, why? More specifically: Why does the BLL need references to SMO when the Utilities class in the DAL already abstracts away the SMO types?
What I want is everything database related to live in the DAL (duh) and only business logic in the BLL (double duh). Is there another way to achieve this using SMO that I have overlooked?
Thank you for your valuable time and answers, I humbly await your responses
Edit:
I've adjusted my solution based on suggestions by Chris, verified that I'm using project refs (I am), readded the references to SMO in the DAL using Muse.VSExtensions to add GAC reference, before I had been browsing and adding manually, then I went ahead and set Copy Local = True for those assemblies just to be doubly sure they're around... but I'm still stuck with this annoying compile error.
I think this boils down to how things are referenced in your solution. So I'm going to take a couple guesses.
It sounds like your DLL references the DAL as an assembly instead of as a project reference.
During compile time Visual Studio copies everything it thinks is necessary to the projects BIN directory. If you reference an external DLL (DAL) then it will copy that DLL only to your BLL's BIN directory.
What you need to do is get it to copy the SMO assemblies as well OR have those SMO assemblies available through the GAC. Personally, I don't like GAC'ing things, so I'll ignore that.
There are three ways of doing this. The easiest is to simply add a reference to those other assemblies to your BLL. Obviously that's not what you want.
The second way is to reference the DAL project as a project reference. This will allow Visual Studio to detect the extra dependencies and copy them accordingly. This is also not exactly what you want as well.
The third way is to copy them as part of a build step. Right click on your BLL project and go to Build Events. In the Pre-build event command line put in the commands to copy the necessary SMO files to your BLL projects BIN directory.
You'll have to do this again for the main service project as well.
It's depressing to answer your own question with a mea culpa, "I'm an idiot"... but, well, I'm an idiot:
In Utilities there was an overload for the offending method which did contain an Smo.Server parameter. I removed that overload (an artifact from testing before refactoring) and voila, problem solved/idiocy confirmed! The interesting thing I learned here is that using the other methods of the Utilities class, which did not have overloads containing Smo objects, was absolutely fine, meaning even with a function in the Utilities class which required an Smo object for a parameter, as long as I didn't call that method or one of its overloads, the references resolved perfectly without a hitch. The new question I have, is why? Why does that overload's existence matter for reference resolution if I call another version of that function from a project higher in the dependency chain? Is there some internal loop where it goes over all versions of a function checking references if any version has been called...
Visual Studio 2008(C#).....I have 3 project in one solution(win application). In every project I've been signing using project properties signing tab to one MySigned.snk. How to manage build configuration so my project doesn't error on every build?
I use [assembly: InternalsVisibleTo("MYproject1, PublicKey=.....")] properties so the other project class can access internal class of base class on other project.
Error becasuse I used backgroundprocess to update every form on my project.But on development environment what suppose I have to do so The project safely on during development? thx before...
I use [assembly:
InternalsVisibleTo("MYproject1,
PublicKey=.....")] properties so the
other project class can access
internal class of base class on other
project.
This is not related to the issue.
In every project I've been signing
using project properties signing tab
to one MySigned.snk. How to manage
build configuration so my project
doesn't error on every build?
I assume it is because the assembly versions are auto-incrementing:
Use project references always. This way, you will make sure everything is built against latest version numbers
Removing * from the AssemblyInfo's assembly version attribute will help here but it is advisable to keep it there.