Microsoft-authentication-library-for-dotnet: [Bug] BadImageException when running in worker role

Created on 13 Nov 2019  路  13Comments  路  Source: AzureAD/microsoft-authentication-library-for-dotnet

I'm using version 4.7.0.0, Create a .net standartd 2.0 library that is wrapping all Graph API.
I use it from a Web API project (.net 4.7.2) and all works good.
I use it from console applications (.net 4.7.2) and all works good.
I tried to use it in Azure cloud service worker role and I get :

System.BadImageFormatException: 'Could not load file or assembly 'Microsoft.Identity.Client, Version=4.7.0.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae' or one of its dependencies. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)'

This drives me crazy...tried to use fusion, check loaded assembly in the app domain...Nada..
Any help with that ?

answered external question

All 13 comments

MSAL uses a technique called "bait and switch", so inside the nuget package there are reference assemblies (which contain only method signatures) and normal assemblies (which contain signatures + actual logic). The reference assemblies are the ones used when you code in Visual Studio, but the runtime uses the nomal (lib) assemblies.

I'm a bit surprised that Azure Cloud Service worker role doesn't support reference assemblies. A few questions - how do you take a dependency on MSAL ? Do you reference it from NuGet? Does your project use the old "packges.config" or the newer mechanism ?

I use NuGet with new PackageReference

We need to escalate this to the Azure Cloud Service folks. @israelolcha - could you provide a few steps that outline how to repro this please?

CC @jmprieur, @henrik-me

Its very easy, Create a cloud service with worker role, in the RoleEntryPoint try to create ConfidentialClientApplicationBuilder and voila you get the exception...

using System;
using System.Diagnostics;
using Microsoft.Identity.Client;
using Microsoft.WindowsAzure.ServiceRuntime;
using MoreLinq;

namespace BackgroundServices
{
    public class WorkerRole : RoleEntryPoint
    {
        private MyWorker _role;

        public override bool OnStart()
        {
            try
            {
                var builder = ConfidentialClientApplicationBuilder.Create(string.Empty);
            }
            catch (Exception)
            {
                // Exception
            }

            _role = new MyWorker ("background");
            return true;
        }

        public override void Run()
        {
            _role.Run();
        }

        public override void OnStop()
        {
            _role.Dispose();
        }
    }
}

Oh, I'm using latest visual studio 2019, Azure tools 2.9

As a workaround, if you unzip the nuget package, you'll find a "lib" folder in there - those are all non-reference assemblies. Just pick the one under netcoreapp (I assume the worker role is a .net core app, otherwise use .net45, which is .net classic).

@jmprieur - who can we escalate this to ?

OK, the hack works. Hope Azure will fix this cause it happens also with StackExchange.Redis 2.0...
thank you very much :)

Thanks for confirming @israelolcha

@bogdan to provide a simple repro

Unsure, why was this closed? The issue still exists, even in the latest nuget version. Checking in a nuget library is not a good solution to the problem.

@one-harsh - this is an external issue. Please

@one-harsh - please open a case with the Azure service owning this. This is not an Identity.SDK problem.

In case people end up here, looking for solution, there is a cleaner way to fix it. Add the following XML snippet to the failing csproj which uses PackageReference:

<Target Name="ReplaceRefWithLib" BeforeTargets="ResolveAssemblyReferences">
  <ItemGroup>
    <_noCopyRefs Include="@(Reference)" Condition="'%(Reference.Private)' == 'false'" />
    <_noCopyRefsByFileName Include="@(_noCopyRefs->'%(FileName)')">
      <OriginalItem>%(Identity)</OriginalItem>
    </_noCopyRefsByFileName>
    <_libByFileName Include="@(ReferenceCopyLocalPaths->'%(FileName)')">
      <OriginalItem>%(Identity)</OriginalItem>
    </_libByFileName>
    <_overlappingRefByFileName Include="@(_noCopyRefsByFileName)" Condition="'@(_noCopyRefsByFileName)' == '@(_libByFileName)' AND '%(Identity)' != ''" />
    <_overlappingLibByFileName Include="@(_libByFileName)" Condition="'@(_noCopyRefsByFileName)' == '@(_libByFileName)' AND '%(Identity)' != ''" />
    <_overlappingRef Include="@(_overlappingRefByFileName->'%(OriginalItem)')" />
    <_overlappingLib Include="@(_overlappingLibByFileName->'%(OriginalItem)')" />
  </ItemGroup>
  <ItemGroup Condition="'@(_overlappingRef)' != ''">
    <Reference Remove="@(_overlappingRef)" />
    <Reference Include="@(_overlappingLib)">
      <Private>false</Private>
    </Reference>
  </ItemGroup>
</Target>
Was this page helpful?
0 / 5 - 0 ratings