I am testing a code targeting .NET standard 2.0, in Visual Studio 2022. The code depends on Polly and Microsoft.Extensions.Http.Polly. The program fails to start with error message :
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Polly, Version=7.0.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc' or one of its dependencies. The system cannot find the file specified.
I found that the error occurred because the build project process does not copy the Polly.dll to folder NetRetry\bin\Debug\netstandard2.0. But why are these assemblies not copied to output folder? I can find these assemblies in .nuget\packages folder.
To reproduce this error
Program.cs
using Microsoft.Extensions.Http;
using Polly;
using System;
using System.Net.Http;
using System.Threading;
class Program
{
static void Main(string[] args)
{
var h = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode != System.Net.HttpStatusCode.OK)
.Or<Exception>()
.RetryAsync(3, (r, count) =>
{
Console.WriteLine($"Log retry {count}");
r.Result.Dispose();
});
var handler = new PolicyHttpMessageHandler(h);
handler.InnerHandler = new HttpClientHandler();
HttpClient c = new HttpClient(handler);
var result = c.GetAsync("https://www.google.com/non-existing", CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
}
}
NetRetry.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<AutoGenerateBindingRedirects>True</AutoGenerateBindingRedirects>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.3" />
<PackageReference Include="Polly" Version="7.2.3" />
</ItemGroup>
</Project>
I tried retargeting project to .NET 5.0 and build the project. This time the assemblies are all copied to folder NetRetry\bin\Debug\net5.0, and the program runs normally.
Manually enable CopyLocalLockFileAssemblies will solve this.
Add to PropertyGroup
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Related
I've created a .Net 6 console app. I added user secrets, but I only get the values defined in the appsettings.json file. I use Visual Studio Professional 2022 version 17.0.4.
Initial steps
Create a new .Net 6 console app from Visual Studio 2022's project templates.
Install the Microsoft.Extensions.Hosting nuget package (version 6.0.0).
Install the Microsoft.Extensions.Configuration.UserSecrets nuget package (version 6.0.0).
Add the appsettings.json file and set Copy to Output Directory to Copy always.
Right-click on the project and select Manage User Secrets.
Code
Program.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.Configure<GlobalSettings>(context.Configuration.GetSection("GlobalSettings"));
services.AddTransient<Worker>();
})
.Build();
var work = host.Services.GetRequiredService<Worker>();
await work.ExecuteAsync();
Worker.cs
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
public class Worker
{
private readonly ILogger<Worker> _logger;
private readonly GlobalSettings _globalSettings;
public Worker(ILogger<Worker> logger, IOptions<GlobalSettings> globalSettings)
{
_logger = logger;
_globalSettings = globalSettings.Value;
}
public async Task ExecuteAsync()
{
_logger.LogInformation(_globalSettings.Foo);
_logger.LogInformation(_globalSettings.Bar);
await Task.CompletedTask;
}
}
GlobalSettings.cs:
public class GlobalSettings
{
public string Foo { get; set; }
public string Bar { get; set; }
}
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<UserSecretsId>deedd476-f5d6-47f4-982e-1645c89789c7</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
appsettings.json:
{
"GlobalSettings": {
"Foo": "Normal Foo",
"Bar": "Normal Bar"
}
}
secrets.json:
{
"GlobalSettings": {
"Foo": "Secret Foo",
"Bar": "Secret Bar"
}
}
What I've tried
Checked whether the user secret id in csproj matched the folder, which it did: C:\Users\Dennis\AppData\Roaming\Microsoft\UserSecrets\deedd476-f5d6-47f4-982e-1645c89789c7
Rebuilded the project.
Closed Visual Studio 2022 and ran it again as administrator.
Created a new project from scratch.
Compared the code with one of my colleague's projects. I couldn't find any difference, but his code works when I run it.
Changed IOptionsSnapshot to IOptions and IOptionsMonitor.
Changed AddTransient to AddSingleton.
Did the same steps, but with a .Net 5 project instead.
Thanks.
I'd misunderstood the way the Host.CreateDefaultBuilder method worked. According to the documentation (docs):
load app IConfiguration from User Secrets when EnvironmentName is 'Development' using the entry assembly
My environment is Production (probably a fallback value). It worked in my colleague's project because it included a launchSettings.json file with the DOTNET_ENVIRONMENT environment variable set to Development.
So the original question What's the correct usage of Microsoft.Build.Evaluation? has the following accepted answer:
project = new Project(projectPath, new Dictionary<string, string>(), "12.0", new ProjectCollection());
This does not work in 2021 with NuGet package Microsoft.Build 16.8.0.
I would like to evaluate a non SDK style project like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
...
<Import Project="..\..\..\Tools\MSBuild\Dayforce.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
Please, observe:
Attempt 1
new Project(projectPath, new Dictionary<string, string>(), "16.0", new ProjectCollection());
Results in:
Microsoft.Build.Exceptions.InvalidProjectFileException: The tools version "16.0" is unrecognized. Available tools versions are "Current".
Attempt 2
new Project(projectPath, new Dictionary<string, string>(), "Current", new ProjectCollection());
Results in:
Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Current\Microsoft.Common.props" was not found. Confirm that the expression in the Import declaration "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Current\Microsoft.Common.props" is correct, and that the file exists on disk.
Attempt 3
new Project(projFilePath, new Dictionary<string, string>
{
["MSBuildExtensionsPath"] = #"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild",
}, "Current", new ProjectCollection());
Results in:
Microsoft.Build.Exceptions.InvalidProjectFileException: The imported project "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Microsoft.CSharp.targets" was not found. Confirm that the expression in the Import declaration "C:\work\CSTool\CSTool\bin\Debug\netcoreapp3.1\Microsoft.CSharp.targets" is correct, and that the file exists on disk.
We are making progress, Microsoft.Common.props seems to have been imported and now we fail on the last import - Microsoft.CSharp.targets
Attempt 4
new Project(projFilePath, new Dictionary<string, string>
{
["MSBuildExtensionsPath"] = #"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild",
["MSBuildBinPath"] = #"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin",
}, "Current", new ProjectCollection());
But the result is:
System.ArgumentException: The "MSBuildBinPath" property name is reserved.
So, what am I missing?
I managed to do what I wanted. However, none of the Microsoft.Build NuGet packages worked as expected by me. I checked all the published versions.
What worked for me is reference the Microsoft.Build Dlls found inside the VS 2019 installation directory. Here is my project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
...
<ItemGroup>
<Reference Include="Microsoft.Build">
<HintPath>..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Build.Framework">
<HintPath>..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Framework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Build.Utilities.Core">
<HintPath>..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Build.Utilities.Core.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
And here is the code that works:
var project = new Project(projFilePath);
foreach (var compileItem in project.AllEvaluatedItems.Cast<ProjectItem>().Where(item => item.ItemType == "Compile"))
{
var filePath = compileItem.EvaluatedInclude;
...
}
I checked the msbuild github repository - it does not use the NuGet packages either. Instead it includes the source code for all the relevant libraries and just builds them. And these dlls work too just as the VS dlls work.
So, what is the deal with the NuGet packages? I do not get it. Opened https://github.com/dotnet/msbuild/issues/6147
There is an open issue regarding loading a project file that explains current caviats for net5 and net6. https://github.com/dotnet/msbuild/issues/3434#issuecomment-774280523
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="17.3.2" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.5.5" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.4.0" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
using Microsoft.Build.Evaluation;
using Microsoft.Build.Locator;
class Program
{
const string ProjectPath = #"C:\tmp\project.csproj";
private static void Main(string[] args)
{
MSBuildLocator.RegisterDefaults();
LoadProject();
}
private static void LoadProject()
{
var buildEngine = new ProjectCollection();
var project = buildEngine.LoadProject(ProjectPath);
Console.WriteLine($"OutputType: {project.GetPropertyValue("OutputType")}");
Console.WriteLine($"TargetFramework: {project.GetPropertyValue("TargetFramework")}");
}
Note how the first usage of MSBuild API has to be in a separate method, because otherwise JIT will try to resolve Microsoft.Build.dll before MSBuildLocator was registered.
In net6 it seems "MSBuildLocator.RegisterDefaults()" is requiered but not in net5.
I did not setup a MSBUILD_EXE_PATH as mentioned by others.
You need to reference the Microsoft.Build.Utilities.Core NuGet package and also set the MSBUILD_EXE_PATH environment variable to either MSBuild.exe or MSBuild.dll
https://web.archive.org/web/20210419051516/https://blog.rsuter.com/missing-sdk-when-using-the-microsoft-build-package-in-net-core/
After this just create a project:
var project = new Project("Path\To\Your\Project");
I am trying do a very simple thing in console app:
using Microsoft.Azure.WebJobs.Extensions.Timers;
using NCrontab;
using System;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
var nCrontabSchedule = CrontabSchedule.Parse("5 4 * * * *");
}
}
}
But it gives me this error:
Severity Code Description Project File Line Suppression State
Error CS0433 The type 'CrontabSchedule' exists in both 'NCrontab.Signed, Version=3.2.20120.0, Culture=neutral, PublicKeyToken=5247b4370afff365' and 'NCrontab, Version=3.2.20120.0, Culture=neutral, PublicKeyToken=null' ConsoleApp3 C:\Users\bowmanzh\source\repos\ConsoleApp3\Program.cs 12 Active
It didn't even finish compile! It’s hard for me to understand what’s going on here, I just want to use a simple thing.
Why is there a version conflict here? In fact, I referenced two packages, this is my .csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="3.0.6" />
<PackageReference Include="NCrontab" Version="3.2.0" />
</ItemGroup>
</Project>
I have already googled, they say something like Aliases, but in fact on my side it doesn't have this property.
I have already tried:
using v2 = NCrontab;
using System;
using Microsoft.Azure.WebJobs.Extensions.Timers;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
v2.CrontabSchedule nCrontabSchedule = v2.CrontabSchedule.Parse("5 4 * * *");
}
}
}
But it didn't work.
How can I solve this problem?
Thank you so much for taking the time to check!
I encountered this same problem. Trying unstalling the NCrontab nuget package and installing NCrontab.Signed instead. This resolved the issue for me.
I am currently building a tool which will support the development of an ASP.NET Core project. This tool uses the Roslyn APIs and other methods for verifying some development requirements (such as project-specific attributes being applied on API Controllers, enforcing naming conventions, and generating some source code for the JavaScript SPA which accesses an API written using the ASP.NET Core Web API template).
In order to do that, I am currently using hardcoded paths to generate code for the SPA app. But in the app's *.csproj file there is actually a "SpaRoot" property specifying where the SPA application is located inside the project:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
...
</PropertyGroup>
...
</Project>
My question is: how can I read the "SpaRoot" property's value using the Roslyn APIs?
I have written a minimum code sample to create a Workspace, open the Solution, and retrieve the Project's reference, which resembles the following:
static async Task Main(string[] args)
{
string solutionFile = #"C:\Test\my-solution.sln";
using (var workspace = MSBuildWorkspace.Create())
{
var solution = await workspace.OpenSolutionAsync(solutionFile);
string projectName = "some-project";
var project = solution.Projects.Single(p => p.Name == projectName);
// How to extract the value of "SpaRoot" from the Project here?
}
I've tried searching on how to extract the "SpaRoot" property from the Project reference, and even went as far as debugging to see if I could spot a way myself. Unfortunately, I came up with no answers to that, and I'm still using hardcoded paths in my original code.
Is it even possible to retrieve the value of .csproj properties of a Project using the current Roslyn APIs?
This is more difficult that you would think :) The Roslyn apis only know what the compiler knows and the compiler is not going to be given anything regarding the SpaRoot property. We can use the MSBuild apis to figure this out though. specifically the Microsoft.Build.Evaluation.Project class.
Some assumptions I am making
You only want to examine .NET Core projects
You will have the .NET Core SDK installed on which ever system runs this tool
So first we want a project file that looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<!--NOTE: If the project you are analyzing is .NET Core then the commandline tool must be as well.
.NET Framework console apps cannot load .NET Core MSBuild assemblies which is required
for what we want to do.-->
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>Latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<!-- NOTE: We put ExcludeAssets="runtime" on all direct MSBuild references so that we pick up whatever
version is being used by the .NET SDK instead. This is accomplished with the Microsoft.Build.Locator
referenced further below. -->
<PackageReference Include="Microsoft.Build" Version="16.4.0" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.8" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="3.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.4.0" />
<!-- NOTE: A lot of MSBuild tasks that we are going to load in order to analyze a project file will implicitly
load build tasks that will require Newtonsoft.Json version 9. Since there is no way for us to ambiently
pick these dependencies up like with MSBuild assemblies we explicitly reference it here. -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
</ItemGroup>
</Project>
and a Program.cs file that looks like this:
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis.MSBuild;
// I use this so I don't get confused with the Roslyn Project type
using MSBuildProject = Microsoft.Build.Evaluation.Project;
namespace loadProject {
class Program {
static async Task Main(string[] args) {
MSBuildWorkspaceSetup();
// NOTE: we need to make sure we call MSBuildLocator.RegisterInstance
// before we ask the CLR to load any MSBuild types. Therefore we moved
// the code that uses MSBuild types to its own method (instead of being in
// Main) so the CLR is not forced to load them on startup.
await DoAnalysisAsync(args[0]);
}
private static async Task DoAnalysisAsync(string solutionPath) {
using var workspace = MSBuildWorkspace.Create();
// Print message for WorkspaceFailed event to help diagnosing project load failures.
workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message);
Console.WriteLine($"Loading solution '{solutionPath}'");
// Attach progress reporter so we print projects as they are loaded.
var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter());
Console.WriteLine($"Finished loading solution '{solutionPath}'");
// We just select the first project as a demo
// you will want to use your own logic here
var project = solution.Projects.First();
// Now we use the MSBuild apis to load and evaluate our project file
using var xmlReader = XmlReader.Create(File.OpenRead(project.FilePath));
ProjectRootElement root = ProjectRootElement.Create(xmlReader, new ProjectCollection(), preserveFormatting: true);
MSBuildProject msbuildProject = new MSBuildProject(root);
// We can now ask any question about the properties or items in our project file
// and get the correct answer
string spaRootValue = msbuildProject.GetPropertyValue("SpaRoot");
}
private static void MSBuildWorkspaceSetup() {
// Attempt to set the version of MSBuild.
var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray();
var instance = visualStudioInstances.Length == 1
// If there is only one instance of MSBuild on this machine, set that as the one to use.
? visualStudioInstances[0]
// Handle selecting the version of MSBuild you want to use.
: SelectVisualStudioInstance(visualStudioInstances);
Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects.");
// NOTE: Be sure to register an instance with the MSBuildLocator
// before calling MSBuildWorkspace.Create()
// otherwise, MSBuildWorkspace won't MEF compose.
MSBuildLocator.RegisterInstance(instance);
}
private static VisualStudioInstance SelectVisualStudioInstance(VisualStudioInstance[] visualStudioInstances) {
Console.WriteLine("Multiple installs of MSBuild detected please select one:");
for (int i = 0; i < visualStudioInstances.Length; i++) {
Console.WriteLine($"Instance {i + 1}");
Console.WriteLine($" Name: {visualStudioInstances[i].Name}");
Console.WriteLine($" Version: {visualStudioInstances[i].Version}");
Console.WriteLine($" MSBuild Path: {visualStudioInstances[i].MSBuildPath}");
}
while (true) {
var userResponse = Console.ReadLine();
if (int.TryParse(userResponse, out int instanceNumber) &&
instanceNumber > 0 &&
instanceNumber <= visualStudioInstances.Length) {
return visualStudioInstances[instanceNumber - 1];
}
Console.WriteLine("Input not accepted, try again.");
}
}
private class ConsoleProgressReporter : IProgress<ProjectLoadProgress> {
public void Report(ProjectLoadProgress loadProgress) {
var projectDisplay = Path.GetFileName(loadProgress.FilePath);
if (loadProgress.TargetFramework != null) {
projectDisplay += $" ({loadProgress.TargetFramework})";
}
Console.WriteLine($"{loadProgress.Operation,-15} {loadProgress.ElapsedTime,-15:m\\:ss\\.fffffff} {projectDisplay}");
}
}
}
}
The Problem
I am trying to create an Azure function leveraging .NET Core 2.2 that accesses a Google Sheet via the Google Sheets API, calls the data, and inserts it into a SQL DB also hosted in Azure.
Here's the error I'm:
This after following this guide.
Note that all the packages are restored.
The code looks roughly like this:
#r "D:\home\site\wwwroot\bin\Google.Apis.Sheets.v4"
#r "D:\home\site\wwwroot\bin\Google.Apis.Auth.OAuth2"
#r "D:\home\site\wwwroot\bin\Google.Apis.Sheets.v4"
#r "D:\home\site\wwwroot\bin\Google.Apis.Sheets.v4.Data"
#r "D:\home\site\wwwroot\bin\Google.Apis.Services"
#r "D:\home\site\wwwroot\bin\System.Data.SqlClient"
using System;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Sheets.v4;
using Google.Apis.Sheets.v4.Data;
using Google.Apis.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Data.SqlClient;
public static string DBConn { get; set; }
public static ILogger Log {get; set;}
public static void Run(TimerInfo myTimer, ILogger log)
{
Log=log;
DBConn="MySQLSrvrConnectionString";
try
{
string spreadsheetId = "MyGoogleSheetId";
SheetsService service = GetSheetService();
if(service!=null)
{
DoSomethingFunc(GetInsertCommand(GetSheetVals(service,spreadsheetId)));
}
}
catch (Exception ex)
{
Log.LogInformation($"Error ({DateTime.Now.ToLongDateString()}): {ex.Message}");
}
finally
{
Log.LogInformation($"Function Completed at: {DateTime.Now.ToLongDateString()}");
}
}
I can provide more if need be.
I've also added a function.proj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Apis.Sheets.v4" Version="1.40.3.1679" />
<PackageReference Include="System.Data.SqlClient" Version="4.6.1" />
</ItemGroup>
</Project>
Research
Haven't found much, honestly.
This is a similar error code, but it seems to a naming issue - having an apostrophe. My app is called "TopicsProvider"
This talks about a webparts XML file. That's not part of my project at all.
Update 1
Paring the code back to its simplest form, I am able to get it to run with the Google API referenced in function.proj. This code works:
using System;
using System.Collections.Generic;
using System.IO;
using System.Data.SqlClient;
public static void Run(TimerInfo myTimer, ILogger log)
{
log.LogInformation($"HELLO");
}
With function.proj like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Apis.Sheets.v4" Version="1.40.3.1679" />
</ItemGroup>
</Project>
What fails is adding using Google.Apis.Sheets.v4; at the top. This gives:
error CS0246: The type or namespace name 'Google' could not be found (are you missing a using directive or an assembly reference?)
Adding #r "Google.Apis.Sheets.v4" or D:\home\site\wwwroot\bin\Google.Apis.Sheets.v4" (note that in the console, there's not a bin folder to begin with...not sure why) to the top, doesn't fix the issue, and changes the error:
2019-09-03T17:48:31.700 [Information] Script for function 'TimerTrigger1' changed. Reloading.
2019-09-03T17:48:31.976 [Error] run.csx(1,1): error CS0006: Metadata file 'Google.Apis.Sheets.v4' could not be found
2019-09-03T17:48:32.051 [Error] run.csx(7,7): error CS0246: The type or namespace name 'Google' could not be found (are you missing a using directive or an assembly reference?)
2019-09-03T17:48:32.075 [Information] Compilation failed.
2019-09-03T17:48:32.549 [Information] Executing 'Functions.TimerTrigger1' (Reason='This function was programmatically called via the host APIs.', Id=bce27519-0236-4754-ac6c-66ae83808801)
2019-09-03T17:48:32.615 [Information] Package references have been updated.
2019-09-03T17:48:32.615 [Information] Restoring packages.
2019-09-03T17:48:32.647 [Information] Starting packages restore
2019-09-03T17:48:36.701 [Information] Restoring packages for D:\local\Temp\32a465b3-8a19-46c8-a533-799a91e1ec09\function.proj...
2019-09-03T17:48:38.434 [Information] Generating MSBuild file D:\local\Temp\32a465b3-8a19-46c8-a533-799a91e1ec09\obj\function.proj.nuget.g.props.
2019-09-03T17:48:38.435 [Information] Generating MSBuild file D:\local\Temp\32a465b3-8a19-46c8-a533-799a91e1ec09\obj\function.proj.nuget.g.targets.
2019-09-03T17:48:38.461 [Information] Restore completed in 2.56 sec for D:\local\Temp\32a465b3-8a19-46c8-a533-799a91e1ec09\function.proj.
2019-09-03T17:48:38.772 [Information] Packages restored.
2019-09-03T17:48:38.996 [Warning] You may be referencing NuGet packages incorrectly. Learn more: https://go.microsoft.com/fwlink/?linkid=2091419
2019-09-03T17:48:39.053 [Error] Function compilation error
Microsoft.CodeAnalysis.Scripting.CompilationErrorException : Script compilation failed.
at async Microsoft.Azure.WebJobs.Script.Description.DotNetFunctionInvoker.CreateFunctionTarget(CancellationToken cancellationToken) at C:\azure-webjobs-sdk-script\src\WebJobs.Script\Description\DotNet\DotNetFunctionInvoker.cs : 314
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at async Microsoft.Azure.WebJobs.Script.Description.FunctionLoader`1.GetFunctionTargetAsync[T](Int32 attemptCount) at C:\azure-webjobs-sdk-script\src\WebJobs.Script\Description\FunctionLoader.cs : 55
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at async Microsoft.Azure.WebJobs.Script.Description.DotNetFunctionInvoker.GetFunctionTargetAsync(Boolean isInvocation) at C:\azure-webjobs-sdk-script\src\WebJobs.Script\Description\DotNet\DotNetFunctionInvoker.cs : 183
2019-09-03T17:48:39.122 [Error] run.csx(1,1): error CS0006: Metadata file 'Google.Apis.Sheets.v4' could not be found
2019-09-03T17:48:39.203 [Error] run.csx(7,7): error CS0246: The type or namespace name 'Google' could not be found (are you missing a using directive or an assembly reference?)
2019-09-03T17:48:39.256 [Error] Executed 'Functions.TimerTrigger1' (Failed, Id=bce27519-0236-4754-ac6c-66ae83808801)
Script compilation failed.
The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)
As I understand it #r isn't necessary, not according to this answer. The packages should load on their own. Neither should I have to upload these files - they're nuget packages that should install automatically.
Update 2
Manually uploading the DLLs does not work. Selecting the file from "Upload", there's a moment where the interface acts like it's loading, but then nothing happens:
What am I missing? Is one of the packages not allowed? Is it a config issue?
Update:
I retry what you do and then it seems worked,
1.create an function.proj file
2.save the file and run:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Apis.Sheets.v4" Version="1.40.3.1679" />
<PackageReference Include="System.Data.SqlClient" Version="4.6.1" />
</ItemGroup>
</Project>
3.add code in .crx file:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
public static string DBConn = "123456";
public static ILogger Log = null;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
Log=log;
DBConn="MySQLSrvrConnectionString";
try
{
string spreadsheetId = "MyGoogleSheetId";
//SheetsService service = GetSheetService();
//if(service!=null)
//{
// DoSomethingFunc(GetInsertCommand(GetSheetVals(service,spreadsheetId)));
//}
}
catch (Exception ex)
{
Log.LogInformation($"Error ({DateTime.Now.ToLongDateString()}): {ex.Message}");
}
finally
{
Log.LogInformation($"Function Completed at: {DateTime.Now.ToLongDateString()}");
}
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
4.then compilation succeeded:
PS: The google .net client library does not have a method called get sheets service.
Original Answer:
This is my code:
public static class Function1
{
public static string DBConn { get; set; }
public static ILogger Log { get; set; }
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
Log = log;
DBConn = "MySQLSrvrConnectionString";
try
{
string spreadsheetId = "MyGoogleSheetId";
}
catch (Exception ex)
{
Log.LogInformation($"Error ({DateTime.Now.ToLongDateString()}): {ex.Message}");
}
finally
{
Log.LogInformation($"Function Completed at: {DateTime.Now.ToLongDateString()}");
}
return (ActionResult)new OkObjectResult($"");
}
}
I delete the
SheetsService service = GetSheetService();
if(service!=null)
{
DoSomethingFunc(GetInsertCommand(GetSheetVals(service,spreadsheetId)));
}
because i don't find which nuget package has these methods.
and this is my function.proj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Apis" Version="1.40.3" />
<PackageReference Include="Google.Apis.Auth" Version="1.40.3" />
<PackageReference Include="Google.Apis.Auth.Mvc" Version="1.40.3" />
<PackageReference Include="Google.Apis.Sheets.v4" Version="1.40.3.1694" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.28" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
and then it works fine. I don't know which packages contain those methods because I don’t know much about Google API. I hope my answer will give you some help.