Using ValueTuple with PackageReference on Azure Cloud Services - c#

I'm trying to convert my c# projects from old to new csproj style, but this breaks my Azure cloud service at runtime because the ReferenceAssembly of System.ValueTuple.dll is copied instead of the implementing assembly.
This is the same problem as described in this closed/abandoned issue.
As my projects are currently targeting .NET 4.6.2, the problem is "solvable" by targeting .NET 4.7+, as that comes with System.ValueTuple and hence does not need to reference it as a NuGet package.
I would like to avoid this situation, if possible, as:
This requires an additional deploy step to install .net 4.7+ runtimes on the worker roles, as they come with .net 4.6.2 installed. https://learn.microsoft.com/en-us/azure/cloud-services/cloud-services-guestos-update-matrix#family-5-releases
This seems as "the easy way out", and I would like to know if the problem can be solved otherwise.
Additional description of the issue:
I'll use:
refDLL for: packages\system.valuetuple\4.5.0\ref\net461\System.ValueTuple.dll, and
libDLL for packages\system.valuetuple\4.5.0\lib\net461\System.ValueTuple.dll.
They are easily distinguishable, as refDLL is 40 kb and libDLL is 78 kb.
The actual code and complete build log file is found here: https://www.dropbox.com/s/kquv5voa19jfonz/AzureCloudService1.zip?dl=0
I have a solution struture as follows:
AzureCloudService1
WorkerRole1 (old csproj)
WorkerRole2 (new csproj)
After building the cloud service the
WorkerRole1\bin\Debug has libDLL.
WorkerRole2\bin\Debug\net461 has libDLL
AzureCloudService1\obj\Debug\WorkerRole1 has libDLL
AzureCloudService1\obj\Debug\WorkerRole2 has refDLL
From the logs, I noticed the following difference between WorkerRole1 and WorkerRole2.
WorkerRole1:
C:\Users\jonas\source\repos\AzureCloudService1\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
CopyLocal = true
FusionName = System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
HintPath = ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
ImageRuntime = v4.0.30319
MSBuildSourceProjectFile = C:\Users\jonas\source\repos\AzureCloudService1\WorkerRole1\WorkerRole1.csproj
MSBuildSourceTargetName = BuiltProjectOutputGroupDependencies
OriginalItemSpec = System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL
ReferenceAssembly = C:\Users\jonas\source\repos\AzureCloudService1\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
ReferenceSourceTarget = ResolveAssemblyReference
ResolvedFrom = {HintPathFromItem}
Version = 4.0.3.0
WorkerRole2:
C:\Users\jonas\.nuget\packages\system.valuetuple\4.5.0\ref\net461\System.ValueTuple.dll
CopyLocal = false
ExternallyResolved = true
FusionName = System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
HintPath = C:\Users\jonas\.nuget\packages\system.valuetuple\4.5.0\ref\net461\System.ValueTuple.dll
ImageRuntime = v4.0.30319
MSBuildSourceProjectFile = C:\Users\jonas\source\repos\AzureCloudService1\WorkerRole2\WorkerRole2.csproj
MSBuildSourceTargetName = BuiltProjectOutputGroupDependencies
NuGetPackageId = System.ValueTuple
NuGetPackageVersion = 4.5.0
NuGetSourceType = Package
OriginalItemSpec = C:\Users\jonas\.nuget\packages\system.valuetuple\4.5.0\ref\net461\System.ValueTuple.dll
Private = false
ReferenceAssembly = C:\Users\jonas\.nuget\packages\system.valuetuple\4.5.0\ref\net461\System.ValueTuple.dll
ReferenceSourceTarget = ResolveAssemblyReference
ResolvedFrom = {HintPathFromItem}
Version = 4.0.3.0
After searching for other related issues on various Microsoft issue trackers, I found this one, which seems related: https://github.com/dotnet/sdk/issues/1738.

Related

MSBuild 16.0 not finding its own dependent assemblies when loaded through MSBuildLocator

I am trying to run MSBuild programmatically from a C# DLL (which will ultimately be loaded from PowerShell), and as a first step from a command-line application. I have used Microsoft.Build.Locator as recommended (or so I reckon) by installing its NuGet package to my project, and adding the following references to my test project:
<Reference Include="Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.Build.Locator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9dff12846e04bfbd, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Build.Locator.1.2.6\lib\net46\Microsoft.Build.Locator.dll</HintPath>
</Reference>
The project targets .NET Framework 4.8, and the source code is as follows:
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Locator;
using System.Collections.Generic;
namespace nrm_testing
{
class Program
{
static void Main(string[] args)
{
MSBuildLocator.RegisterDefaults();
DoStuff();
}
static void DoStuff()
{
using (var projectCollection = new ProjectCollection())
{
var buildParameters = new BuildParameters
{
MaxNodeCount = 1 // https://stackoverflow.com/q/62658963/3233393
};
var buildRequestData = new BuildRequestData(
#"path\to\a\project.vcxproj",
new Dictionary<string, string>(),
null,
new string[0],
null
);
var result = BuildManager.DefaultBuildManager.Build(buildParameters, buildRequestData);
}
}
}
}
Upon entering the using block, I receive the following exception:
System.IO.FileNotFoundException: 'Could not load file or assembly 'System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.'
The Modules window shows that MSBL did successfully locate my VS2019 installation:
Microsoft.Build.dll 16.07.0.37604 C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.dll
Microsoft.Build.Framework.dll 16.07.0.37604 C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Framework.dll
Microsoft.Build.Locator.dll 1.02.6.49918 C:\dev\nrm3-tests\nrm\nrm-testing\.out\AnyCPU-Debug\Microsoft.Build.Locator.dll
System.Runtime.CompilerServices.Unsafe.dll is indeed present besides the located MSBuild assemblies, in version 4.0.6.0 (according to DotPeek).
What could be causing this error, and how could I fix it?
My attempts so far:
I have found this question, but the linked GitHub issue is still open and I'm unsure whether it's the same problem.
I have managed to get an binding redirects working, but I don't think I can use them from within a DLL, so that's a dead end.
Adding the System.Runtime.CompilerServices.Unsafe NuGet package to the project (and verifying that it is indeed copied alongside the project's executable) does nothing (thanks magicandre1981 for the suggestion).
Switching from packages.config to PackageReference (as suggested by Perry Qian), with no change in behaviour.
After a lot of fiddling with different ideas, I ended up writing this workaround based on manual assembly resolution.
RegisterMSBuildAssemblyPath detects when Microsoft.Build.dll gets loaded, and memorizes its directory. Upon subsequent assembly load failures, RedirectMSBuildAssemblies checks if the missing assembly exists inside that path, and loads it if it does.
class Program
{
private static string MSBuildAssemblyDir;
static void Main(string[] args)
{
MSBuildLocator.RegisterDefaults();
Thread.GetDomain().AssemblyLoad += RegisterMSBuildAssemblyPath;
Thread.GetDomain().AssemblyResolve += RedirectMSBuildAssemblies;
DoStuff();
}
private static void RegisterMSBuildAssemblyPath(object sender, AssemblyLoadEventArgs args)
{
var assemblyPath = args.LoadedAssembly.Location;
if (Path.GetFileName(assemblyPath) == "Microsoft.Build.dll")
MSBuildAssemblyDir = Path.GetDirectoryName(assemblyPath);
}
private static Assembly RedirectMSBuildAssemblies(object sender, ResolveEventArgs args)
{
if (MSBuildAssemblyDir == null)
return null;
try
{
var assemblyFilename = $"{args.Name.Split(',')[0]}.dll";
var potentialAssemblyPath = Path.Combine(MSBuildAssemblyDir, assemblyFilename);
return Assembly.LoadFrom(potentialAssemblyPath);
}
catch (Exception)
{
return null;
}
}
static void DoStuff()
{
// Same as before
}
}
I'm pretty sure there are (many) corner cases that will make this fail, but it will do for now.
Actually, this is an real issue for a long time for packages.config nuget management format. And Microsoft's recommended solution for this problem is to add a bindingRedirect.
Usually, you can use this node in xxx.csproj file to automatically generate bindingredirect.
However, for some specific dlls, this node may not work due to serveral reasons. And it is still an issue on the current packages.config nuget management format as your said.
Suggestion
As a suggestion, you could use the new PackageReference nuget manage format instead since VS2017. This format is simple, convenient and efficient.
Also, when you use this format, first, you should make a backup of your project.
Just right-click on the packages.config file-->click Migrate packages.config to PackageReference.
Besides, I have also reported this issue on DC Forum and I hope the team will provide a better suggestion.

Cake Build - Update NuGet package to the newest version

I have a solution with 5 projects in it. Every project is deployed via a nuget-push. Some projects reference other projects via nuget. In order to work properly these nuget-packages have to be updated before they are pushed.
For this we use Cake-Build but the nuget update is not working on core/standard projects. Instead it is necessary to use remove --> add, which is not working for me?
How can I handle this?
Example:
Project A v1.0.0
Project B v1.0.0
Project C v1.0.0
Reference to A v1.0.0
Reference to B v1.0.0
Now the Build-Script would compile A and B, increment the version to v1.0.1, and push the nuget-package. Before C is build the nuget packages to A & B needs to be updated.
Example:
Project A v1.0.1
Project B v1.0.1
Project C v1.0.1
Reference to A v1.0.1
Reference to B v1.0.1
How I'm able to update the packages via Cake-Build?!?
If you use project references and build as part of same solution, you should be able to get everything referenced correctly. That's how Cake itself is built.
Cake.exe / dll depends on
Cake.Core
Cake.Common which depends on
Cake.Core
When we i.e. build 0.30.0 we pass that version as common MSBuildSettings to Restore. Build and Pack. Rough example
string configuration = "Release",
version = "0.30.0",
semVersion = "0.30.0"; // for pre-release this is suffixed i.e. -alpha-001
DotNetCoreMSBuildSettings msBuildSettings = new DotNetCoreMSBuildSettings()
.WithProperty("Version", semVersion)
.WithProperty("AssemblyVersion", version)
.WithProperty("FileVersion", version);
DotNetCoreRestore("./src/Cake.sln", new DotNetCoreRestoreSettings
{
Verbosity = DotNetCoreVerbosity.Minimal,
Sources = new [] { "https://api.nuget.org/v3/index.json" },
MSBuildSettings = msBuildSettings
});
DotNetCoreBuild("./src/Cake.sln", new DotNetCoreBuildSettings()
{
Configuration = configuration,
NoRestore = true,
MSBuildSettings = msBuildSettings
});
var projects = GetFiles("./src/**/*.csproj");
foreach(var project in projects)
{
DotNetCorePack(project.FullPath, new DotNetCorePackSettings {
Configuration = configuration,
OutputDirectory = "./nuget,
NoBuild = true,
NoRestore = true,
IncludeSymbols = true,
MSBuildSettings = msBuildSettings
});
}
A project reference in .NET Core csproj looks like
<ProjectReference Include="..\Cake.Core\Cake.Core.csproj" />

Could not load file or assembly 'Microsoft.Azure.Graphs'

I've created an Azure Function to connect to a CosmosDB Graph. I'm using the nuget package Microsoft.Azure.Graph 0.3.0-preview and am getting the error when I hit the endpoint of the function.
Exception while executing function: GetTrain -> Could not load file or assembly 'Microsoft.Azure.Graphs, Version=0.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
The code for the function is below, but it doesn't even get as far as that.
[FunctionName("GetThing")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "thing/{id}")]HttpRequestMessage req, string id, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
string endpoint = ConfigurationManager.AppSettings["endpoint"];
string authKey = ConfigurationManager.AppSettings["authkey"];
string db = ConfigurationManager.AppSettings["db"];
string collection = ConfigurationManager.AppSettings["collection"];
DocumentClient client = new DocumentClient(new Uri(endpoint), authKey,
new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp });
DocumentCollection graph = await client.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(db),
new DocumentCollection { Id = collection },
new RequestOptions { OfferThroughput = 1000 });
IDocumentQuery<dynamic> query = client.CreateGremlinQuery<dynamic>(graph, $"g.V('{id}').has('thing')");
// Fetching the name from the path parameter in the request URL
return req.CreateResponse(HttpStatusCode.OK, "Hello");
}
Update
Seems there is a build warning, completely didn't see that. Any thoughts?
Warning MSB3270 There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "C:\Users\blah.nuget\packages\microsoft.azure.graphs\0.3.0-preview\lib\net461\Microsoft.Azure.Graphs.dll", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.
This issue is resolve for packages Microsoft.Azure.Graphs >= 0.3.1-preview.
As others have pointed out, the issue was that Microsoft.Azure.Graphs was previously targeting x64 platform only. New versions of the assembly are now compiled targeting AnyCPU (MSIL).
Try the 0.2.4-preview version of the Microsoft.Azure.Graphs package. There seems to be an issue with the 0.3.0 release. See recent comments on the SDK page:
https://learn.microsoft.com/en-us/azure/cosmos-db/graph-sdk-dotnet
And I added a GitHub issue:
https://github.com/Azure/azure-documentdb-dotnet/issues/361
This issue on github fixes everything to me https://github.com/Azure/azure-documentdb-dotnet/issues/361 only change Any Cpu to x64

Accessing Visual Studio MEF components/IComponentModel in a remotely controlled Visual Studio instance

For an integration test scenario I am trying to start/control a Visual Studio instance remotely and access some of its public MEF components.
Starting and controlling an instance and accessing services via the DTE works fine:
var dte = Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.DTE.15.0", true), true) as DTE;
ServiceProvider sp = new ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte);
IVsActivityLog log = sp.GetService(typeof(SVsActivityLog)) as IVsActivityLog;
What doesn't work is the standard way of getting the IComponentModel which can in turned be used to access the MEF components. GetService() returns something but the cast results in null:
var componentModel = sp.GetService(typeof(SComponentModel)) as IComponentModel
Is there another way of getting access to the MEF components or is this scenario not supported?
I was having a similar issue when trying to run an extension I wrote for SSMS 17 on SSMS 18. In my solution, Microsoft.VisualStudio.ComponentModelHost version 14.0.0.0 was referenced and when running it on SSMS 17 everything worked just fine. The line:
var componentModel = serviceProvider.GetService(typeof(SComponentModel));
returned an instance of Microsoft.VisualStudio.ComponentModelHost.ComponentModel from the Microsoft.VisualStudio.ComponentModelHost.Implementation version 14.0.0.0 assembly.
When running:
componentModel.GetType()
in the Immediate Window I would get:
{Name = "ComponentModel" FullName = "Microsoft.VisualStudio.ComponentModelHost.ComponentModel"}
Assembly: {Microsoft.VisualStudio.ComponentModelHost.Implementation, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
...
But when debugging the same extension (from the same solution referencing Microsoft.VisualStudio.ComponentModelHost version 14.0.0.0) on SSMS 18 the line:
var serviceProvider = serviceProvider.GetService(typeof(SComponentModel));
returned and instance from a newer assembly.
componentModel.GetType()
{Name = "ComponentModel" FullName = "Microsoft.VisualStudio.ComponentModelHost.ComponentModel"}
Assembly: {Microsoft.VisualStudio.ComponentModelHost.Implementation, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
...
And when trying to cast it to IComponentModel, the cast would fail.
The solution for me was to reference Microsoft.VisualStudio.ComponentModelHost version 15.0.0.0 in the solution since the IComponentModel interface comes from that assembly.
Hope it helps

ServiceStack client on a Xamarin.iOS project

I am trying to use the ServiceStack clients on a Xamarin iOS project and when debugging it I have the following exception:
“System.ArgumentException: PclExport.Instance needs to be
initialized”.
The code that produces the exception is the following:
try
{
string strReadParam = this.xmlParser.GetString("SyncUrl");
CommonStatic.SyncWSUrl = strReadParam;
var client = new JsonServiceClient(CommonStatic.SyncWSUrl);
client.Timeout = new TimeSpan(0, 0, 0, 5, 0);
var response = client.Get(new mSalesCheckConnectionRequest { DBSource = CommonStatic.DBSource, DBSourceInstance = CommonStatic.DBSourceInstance, DBName = CommonStatic.DBName, DBUsername = CommonStatic.DBUsername, DBPassword = CommonStatic.DBPassword });
return;
}
catch (System.Net.WebException wex)
{
}
I am using ServiceStack.Interfaces, ServiceStack.Client.Pcl and ServiceStack.Text.Pcl all having version 4.0.34. Additionally I referenced Newtonsoft.Json at version 6.0.7.
After some research I realized that the PCL provider for iOS is not registered automatically, so I added “IosPclExportClient.Configure();” before instantiating the new Json Service Client and a I referenced ServiceStack.Pcl.iOS.dll at version 4.0.0.0.
The result is the following error:
“Cannot include both 'monotouch.dll' and 'Xamarin.iOS.dll' in the same Xamarin.iOS project - 'Xamarin.iOS.dll' is referenced explicitly, while 'monotouch.dll' is referenced by 'ServiceStack.Pcl.iOS, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null'.”
Is there is any suggestion of resolving this problem?
Thank you in advance
You need to call IosPclExportClient.Configure(); when you application starts to initialise the PCL Export Client before use in iOS applications.
So in your Main method:
static void Main (string[] args)
{
// Configure ServiceStack Client
IosPclExportClient.Configure();
// Set AppDelegate
UIApplication.Main (args, null, "AppDelegate");
}
and a I referenced ServiceStack.Pcl.iOS.dll at version 4.0.0.0.
The PCL specific NuGet packages of ServiceStack are no longer maintained, as they have been merged into the main NuGet package using specific profile.
You should only be including the ServiceStack.Client package in your project. So remove all references to ServiceStack in your project, clean the build, and add just ServiceStack.Client.
If you reference ServiceStack.Client.Pcl was well as ServiceStack.Client you will get a conflict.

Categories

Resources