-2

I am working on a simple interface to SharePoint via Graph API. I have created a project that references Azure.Core, Azure.Identity, Microsoft.Graph, and other dependencies required to make calls via Microsoft's Graph API. This project is our API project and other projects will reference this API project to be able to talk to SharePoint via Graph API. I am trying to contain all the third party references within this project so that projects that reference the API project do not need to reference the dependencies that this project references. For example, Microsoft.Graph.

I have created a Unit Test project in the same solution and referenced the API project. Then I made a simple unit test that creates the class that has all the methods that talk to SharePoint from the API project. But when I run the unit test it complains that it is missing dependencies that are present in the API project. This is one of the exceptions:

System.IO.FileLoadException: Could not load file or assembly
'Microsoft.Identity.Client, Version=4.56.0.0, Culture=neutral,
PublicKeyToken=0a613f4dd989e8ae' or one of its dependencies. The located assembly's 
manifest definition does not match the assembly reference. (Exception from HRESULT: 
0x80131040) ---> System.IO.FileLoadException: Could not load file or assembly 
'Microsoft.Identity.Client, Version=4.54.1.0, Culture=neutral, 
PublicKeyToken=0a613f4dd989e8ae' or one of its dependencies. The located assembly's 
manifest definition does not match the assembly reference. (Exception from HRESULT: 
0x80131040)

I have checked the API project and it contains this specific version of the assembly from the exception. I can build the API project fine also, obviously.

My question is thus, how do I make it so that projects that reference this API project will not need to reference the dependencies in the API project? I want to decouple it completely. Is that even possible in this way?

Code examples:

In the API project there is a constructor that creates the class that handles the calls to Graph:

public class GraphApi : IGraphApi
{
    GraphServiceClient graphClient;
    private bool disposed;
    
    public GraphApi(GraphApiConstructorParameters parameters)
    {
        string[] scopes = new[] { "https://graph.microsoft.com/.default" };
        // https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
        var clientSecretCredential = new ClientSecretCredential(parameters.TenantId, parameters.ClientId, parameters.ClientSecret);
        graphClient = new GraphServiceClient(clientSecretCredential, scopes);
    }
}

Then in the unit test:

[TestMethod]
public void GetGroup()
{
    GraphApi GraphApi = new GraphApi(parameters); // <-- this line causes the exception.
    var group = graphApi.GetGroup("guidofgroup");
}
3
  • 1
    Which version of dotnet is this? Is there another project in the same solution referencing a different version of the dependency?
    – pjc50
    Commented Oct 5, 2023 at 12:18
  • 2
    I don't think you have a reference issue, which is a compile-time problem. You have a runtime error that indicates a deployment issue. Even though your code doesn't have to set a reference to those libraries, the libraries need to be present on the machine at runtime. Are you including them in your deployment package?
    – John Wu
    Commented Oct 5, 2023 at 20:41
  • 1
    It think this is a build/deployment issue, which is better suited for Stackoverflow than SWE.SE, hence voting to close. Please check other SO questions like this one and this one first before you move the question over to SO.
    – Doc Brown
    Commented Oct 6, 2023 at 6:05

1 Answer 1

0

My question is thus, how do I make it so that projects that reference this API project will not need to reference the dependencies in the API project? I want to decouple it completely. Is that even possible in this way?

If you only mean you don't want to have to do the extra clicks in the NuGet manager, then yes, the under the hood references can be done automatically by later .NET versions. But it doesn't mean it's decoupled, it only means the coupling got easier to manage with fewer clicks and overhead.

As long as your project and this project get loaded into the same AppDomain (for example because your project references the assembly), that is not possible.

If you really want to decouple this completely, you will have to make two different AppDomains that run those two different assemblies and all their respective dependencies.

The easiest way to do this would be to actually make it two different projects that connect through an external mechanism. For example you could make your API a WebApi projects with Swagger and connect your project though an auto-generated client. Then they are absolutely decoupled and as long as you don't change the interface, any internal changes in either project will not impact the other solution. You could even have the same dependency but in different versions in both solutions.

You can have multiple AppDomains in one executable, but I think that would really be a bit much for your example. It makes your solution more complex and more error prone (not because of any .NET shortcomings, but because developers are failable and the more opportunities to fail they have, the more bugs will appear).

Maybe "the dependencies are handled for me under the hood in more recent .NET versions" is all you really need for your business case.

5
  • 1
    On one hand. this answer recommends to use a recent .Net framework version. On the other hand, it makes some statements about multiple AppDomains, which were thrown over board by Microsoft since .Net Fw 5. / .Net Core. Maybe you could clarify which .Net framework version you exactly have in mind, or which was the latest .Net fw version which had issues with transitive NuGet dependencies? It was actually new to me such issues existed.
    – Doc Brown
    Commented Oct 6, 2023 at 13:53
  • 1
    There is no issue with transitive dependencies. But it is a dependency. So if your assembly needs Dependency.dll in version 11 and your other dependency need Dependency.dll version 13 and there are breaking changes in between so you cannot just pick one for both, then you are out of luck. Because even a transitive dependency is a dependency. To be truly free of such a dependency, you need to decouple it. AppDomains where one way to do so... I guess that doesn't work anymore? How do people write plugin systems in .NET Core? Just hope their plugins don't have dependencies?
    – nvoigt
    Commented Oct 6, 2023 at 14:13
  • "references can be done automatically by later .NET versions" - so in which older .Net fw version, precisely, did this not work? Please clarify!
    – Doc Brown
    Commented Oct 6, 2023 at 17:24
  • ... and about the missing AppDomain feature in .Net core, look here on SO, for example.
    – Doc Brown
    Commented Oct 6, 2023 at 18:12
  • No clarification for what I asked above within 4 days?
    – Doc Brown
    Commented Oct 10, 2023 at 12:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.