I have a function that I'm porting from Azure Functions v1 to v2, and as part of that I've run into an issue updating my unit tests which create a stubbed HttpRequestMessage. Here's the code that works on Functions v1, targeting .NET Framework 4.7
public class FunctionExample
{
[FunctionName(nameof(SomeFunction))]
public static async Task<HttpResponseMessage> SomeFunction
(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "SomeFunction")]
HttpRequestMessage request
)
{
var body = await request.Content.ReadAsStringAsync();
if (string.IsNullOrEmpty(body))
{
return request.CreateResponse(HttpStatusCode.BadRequest, "Bad job");
}
else
{
return request.CreateResponse(HttpStatusCode.OK, "Good job");
}
}
}
And my test code
public class FunctionExampleTests
{
[Test]
public async Task TestSomeFunction()
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("http://localhost/"),
Content = new StringContent("", Encoding.UTF8, "application/json")
};
request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey,
new HttpConfiguration());
var response = await FunctionExample.SomeFunction(request);
var content = await response.Content.ReadAsStringAsync();
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
Assert.That(content, Is.EqualTo("\"Bad job\""));
}
}
After porting to v2, my function project csproj file looks like this. The only differences are that I'm no longer targeting full framework, and the addition of the AzureFunctionsVersion node.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.24" />
</ItemGroup>
</Project>
And this is the csproj for my test project after retargeting to .NET Core 2.0
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FunctionExample\FunctionExample.csproj" />
</ItemGroup>
</Project>
Previously, I was using the answers to this question to properly stub out HttpRequestMessage but that no longer appears to work.
When I try to compile this, I get the following compilation errors
Error CS0246 The type or namespace name 'HttpConfiguration' could not be found (are you missing a using directive or an assembly reference?)
Error CS0103 The name 'HttpPropertyKeys' does not exist in the current context
So if I just remove the line, hoping that the fix is no longer needed
request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
Instead I get this error message
System.InvalidOperationException : The HttpRequestMessage instance is not properly initialized. Use HttpRequestMessageHttpContextExtensions.GetHttpRequestMessage to create an HttpRequestMessage for the current request.
Trying to follow the error message's directions didn't prove fruitful to me, I tried to set the HttpContext like was done in this question
request.Properties.Add(nameof(HttpContext), new DefaultHttpContext());
But that gave me a different error (same as in the question)
System.ArgumentNullException : Value cannot be null.
Parameter name: provider
Azure Functions is somewhat based on ASP.NET MVC WebApi, which has had some changes for .NET Core. HttpConfiguration for example doesn't appear to be available in any packages that target .NET Core/Standard. In order to fix this, I had to install a couple of packages in my test project, namely Microsoft.AspNetCore.Mvc for AddMvc() and Microsoft.AspNetCore.Mvc.WebApiCompatShim for .AddWebApiConventions(), which:
Provides compatibility in ASP.NET Core MVC with ASP.NET Web API 2 to simplify migration of existing Web API implementations
So I added these to my test project
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.2.0" />
and now my test project looks like this
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.11.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.2.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FunctionExampleFunction\FunctionExampleFunction.csproj" />
</ItemGroup>
</Project>
To mock the services that the ArgumentNullException was implying were missing (which in this case I think are MediaTypeFormatters), I had to essentially bootstrap MVC to get the HttpContext initialized properly.
[Test]
public async Task TestSomeFunction()
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("http://localhost/"),
Content = new StringContent("", Encoding.UTF8, "application/json")
};
var services = new ServiceCollection()
.AddMvc()
.AddWebApiConventions()
.Services
.BuildServiceProvider();
request.Properties.Add(nameof(HttpContext), new DefaultHttpContext
{
RequestServices = services
});
var response = await FunctionExample.SomeFunction(request);
var content = await response.Content.ReadAsStringAsync();
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
Assert.That(content, Is.EqualTo("\"Bad job\""));
}
And that makes the test compile, run, and pass.
Related
After spending way too much time, I still can't make Roslyn to load simple C# project.
Project source:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.11.0" />
</ItemGroup>
</Project>
Code that is trying to load:
using System;
using Microsoft.CodeAnalysis.MSBuild;
namespace Metrics5
{
class Program
{
static void Main(string[] args)
{
using var workspace = MSBuildWorkspace.Create();
workspace.LoadMetadataForReferencedProjects = true;
var currentProject = workspace.OpenProjectAsync(#"C:\work\Metrics5\Metrics5.csproj").Result;
var diagnostics = workspace.Diagnostics;
foreach(var diagnostic in diagnostics)
{
Console.WriteLine(diagnostic.Message);
}
}
}
}
It says:
Msbuild failed when processing the file 'C:\work\Metrics5\Metrics5.csproj' with message: The SDK 'Microsoft.NET.Sdk' specified could not be found. C:\work\Metrics5\Metrics5.csproj
After I add MSBuildSDKsPath as environment value MSBuildSDKsPath=C:\Program Files\dotnet\sdk\5.0.301\Sdks it seems to pass that step and stuck in another:
Msbuild failed when processing the file 'C:\work\Metrics5\Metrics5.csproj' with message: The imported project "C:\work\Metrics5\bin\Debug\net5.0\Current\Microsoft.Common.props" was not found. Confirm that the expression in the Import de
claration "C:\work\Metrics5\bin\Debug\net5.0\Current\Microsoft.Common.props" is correct, and that the file exists on disk. C:\Program Files\dotnet\sdk\5.0.301\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.props
And from here I'm not sure how to proceed, am I missing some nuget package?
Do I need to install additionally something?
Add reference to Microsoft.Build.Locator
I used the next packages:
<ItemGroup>
<PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.11.0" />
</ItemGroup>
Then register the instance of MSBuild using MSBuildLocator:
//add this line before using MSBuildWorkspace
MSBuildLocator.RegisterDefaults(); //select the recent SDK
using var workspace = MSBuildWorkspace.Create();
You Can control the version of MsBuild:
var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances();
//select NET5, or whatever by modifying Version.Major
var instance = visualStudioInstances.FirstOrDefault(x => x.Version.Major.ToString() == "5");
MSBuildLocator.RegisterInstance(instance);
Setting up an Azure Function that references other netstandard projects which on their turn reference Microsoft.Extensions.Logging.
When the Function runs locally without any references to the other projects, everything starts fine. But as soon as I add a reference to one of the other projects, I get the following exception at startup:
TestTrigger: Microsoft.Azure.WebJobs.Host: Error indexing method 'TestTrigger'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'log' to type ILogger. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
This is the initial code I have for my Timer function
public class TestTrigger
{
private ITester _tester;
public TestTrigger(ITester tester)
{
_tester = tester;
}
[FunctionName("TestTrigger")]
public void Run([TimerTrigger("* * * * * *")] TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.UtcNow}");
_tester?.TestMethod().Wait();
}
}
I have my dependencies injected in the following Startup class
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var cfgBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile($"appsettings.json", true, true)
.AddJsonFile($"appsettings.dev.json", true, true)
.AddEnvironmentVariables();
var configuration = cfgBuilder.Build();
builder.Services
.AddSingleton<ITester, Tester>()
.AddLogging()
.AddOptions();
}
}
The custom class that implements ITester is part of a netstandard 2.0 project that references the Microsoft.Extensions.Logging.Abstractions 3.0.0.0 nuget package. The functions project itself is a netcoreapp2.1 project that also references that same nuget package, as well as the Microsoft.NET.Sdk.Functions 1.0.29, the Microsoft.Azure.Functions.Extensions 1.0.0 and the Microsoft.NETCore.App 2.1.0 package.
For reference, the csproj files:
The function project
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AzureFunctionsVersion></AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.29" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TestLibrary\TestLibrary.csproj" />
</ItemGroup>
</Project>
The referenced project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.0.0" />
</ItemGroup>
</Project>
I am quite sure it's reference issue, but cannot put my hands on it.
Any help?
Have reproduced your error:
Seems the error comes from the reference project.
Solution:
Downgrading the version of Microsoft.Extensions.Logging.Abstractions to 2.2.0.
Cause:
The binding engine doesn't recognize your parameter's type as being the same since they're from different assemblies.
I'm using dotnet standard 2.0 (Visual Studio 2017) for gRPC. This is how my whole project looks like:
Messages.proto
syntax = "proto3";
package Messages;
message IdRequest{
int32 id = 1;
}
message NameResponse{
string name=1;
}
Name.proto
syntax = "proto3";
package Services;
import public "proto/messages.proto";
service NameService{
rpc GetNameById(Messages.IdRequest) returns (Messages.NameResponse);
}
Common.proj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="proto\messages.proto" />
<None Remove="proto\name.proto" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
<PackageReference Include="Grpc" Version="2.24.0" />
<PackageReference Include="Grpc.Core" Version="2.24.0" />
<PackageReference Include="Grpc.Tools" Version="2.24.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Protobuf Include="proto\messages.proto" />
<Protobuf Include="proto\name.proto" />
</ItemGroup>
</Project>
The project builds successfully however the final Common.dll has no Messages namespace and I cannot really reference IdRequest or NameResponse.
So where am I making the mistake that hides Messages namespace?
In your project file into the Protobuf-tag you need to add the GrpcServices attribute or else no code is created:
<ItemGroup>
<Protobuf Include="proto\messages.proto" GrpcServices="Server" />
<Protobuf Include="proto\name.proto" GrpcServices="Server" />
</ItemGroup>
I know this is so old, but in case it is helpful for someone else. The documentation for gRPC has greatly improved since the asking of this question.
Looking at the tags associated, but also from the discussions and screenshots from here, I'm going to make the assumption that the project was working with csharp, as this makes a difference. I believe the namespaces are not generated correctly because the option "csharp_namespace" is missing.
The service will also have its namespace changed because of this amendment.
Message.proto:
syntax = "proto3";
package Messages;
option csharp_namespace = "Messages";
message IdRequest{
int32 id = 1;
}
message NameResponse{
string name=1;
}
Name.proto:
syntax = "proto3";
package Services;
option csharp_namespace = "Messages";
import "proto/Messages.proto";
service NameService{
rpc GetNameById(Messages.IdRequest) returns (Messages.NameResponse);
}
I am trying to call api using Flurl and here is my request which only fails on my testserver but works on live server and localhost as well
PickUp responseAsPickUpPointServiceResponse = null;
try
{
responseAsPickUpPointServiceResponse =
await new Flurl.Url(_baseUrl + "/rest//v1/servicepoint/findByPostalCode.json")
.SetQueryParam("apikey", APIKEY_WEB1)
.SetQueryParam("countryCode", countrycode)
.SetQueryParam("postalCode", zipcode)
.WithHeader("Accept", "application/json;charset=UTF-8")
.GetJsonAsync<PickUp>();
}
BUt it fails with error
Method not found: 'System.Threading.Tasks.Task`1 Flurl.Http.GeneratedExtensions.GetJsonAsync(Flurl.Http.IFlurlRequest, System.Threading.CancellationToken, System.Net.Http.HttpCompletionOption)
Has anyone idea how to fix this?
Same here, I got the same error Method not found [...] GetJsonAsync when running my integration tests although it was working well with unit tests.
In my case, there were two projects where Flurl.Http versions mismatched :
main.csproj
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Flurl" Version="3.0.0" />
<PackageReference Include="Flurl.Http" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\other\imported.csproj" />
</ItemGroup>
</Project>
imported.csproj
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Flurl" Version="2.8.2" />
<PackageReference Include="Flurl.Http" Version="2.4.2" />
</ItemGroup>
</Project>
The error was fixed by bumping Flurl version to 3.0.1 everywhere :
In both files :
<PackageReference Include="Flurl" Version="3.0.1" />
<PackageReference Include="Flurl.Http" Version="3.0.1" />
I want to integration test an ASP.NET Core MVC WebSite. I started by adding an empty MVC WebApplication project:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
</ItemGroup>
</Project>
It runs and shows the ASP.NET Core MVC sample page.
Then I added an XUnit-Project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WebApplication1\WebApplication1.csproj" />
</ItemGroup>
</Project>
Where I added the nuget package Microsoft.AspNetCore.TestHost.
The following test fails with a CompilationFailedException:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using WebApplication1;
using Xunit;
public class UnitTest1
{
[Fact]
public async void Test1()
{
var builder = new WebHostBuilder()
.UseContentRoot(#"C:\path\to\WebApplication1")
.UseStartup<Startup>();
var server = new TestServer(builder);
var client = server.CreateClient();
var _ = await client.GetAsync("/");
}
}
Exception details:
Microsoft.AspNetCore.Mvc.Razor.Compilation.CompilationFailedException : One or more compilation failures occurred:
oxhek45x.0i3(4,62): error CS0012: The type 'Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
oxhek45x.0i3(4,81): error CS0518: Predefined type 'System.String' is not defined or imported
oxhek45x.0i3(4,110): error CS0518: Predefined type 'System.Type' is not defined or imported
oxhek45x.0i3(4,11): error CS0518: Predefined type 'System.Void' is not defined or imported
#542 and #2981 describe similar problems.
I tried adding this to the test project, but it didn't help:
<ItemGroup>
<Reference Include="netstandard" />
</ItemGroup>
And I tried replacing the MetadataReferenceFeature as described in #2981.
Found a "solution" that works for me:
Set the Content Root to the folder of the web project
Copy the *.deps.json file from the output folder of the web project to the output folder of the test project
This process will be made easier in ASP.NET Core 2.1. Found the solution here. More details about the new feature in 2.1 can be found here.
This article explains how to automize step 2:
Just add this in to your test csproj-file:
<Copy SourceFiles="%(DepsFilePaths.FullPath)" DestinationFolder="$(OutputPath)" Condition="Exists('%(DepsFilePaths.FullPath)')" />