Why is Azure Function v2 unable to bind to CloudTable? - c#

I'm trying to run an HTTP triggered v2 function in Visual Studio 2019.
It's supposed to write its output into an Azure Storage Table called "history".
I've decorated one my functions with
[return: Table("history")]
and I make it return a subclass of TableEntity.
This results in an exception about it being "unable to bind Table to CloudTable". The reason for the exception is a check within the CloudStorageAccount client's code:
bool bindsToEntireTable = tableAttribute.RowKey == null;
if (bindsToEntireTable)
{
// This should have been caught by the other rule-based binders.
// We never expect this to get thrown.
throw new InvalidOperationException("Can't bind Table to type '" + parameter.ParameterType + "'.");
}
Another function binds to a CloudTable as an input parameter and suffers from the same exception.
Although binding to CloudTable should work (https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-table#input---c-example---cloudtable) it apparently does not.
Is this a bug in the client SDKs for Azure Storage or am I doing something wrong? I'm referencing these Nuget packages:
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="1.8.3" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="3.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.29" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />

The problem is a version mismatch of two Nuget packages. When creating a new solution I was unable to replicate the issue and binding to CloudTable worked just fine. Comparing to my solution revealed that my function project referenced another project which had a dependency on
WindowsAzure.Storage (9.3.3)
because I needed the TableEntity type in there.
And now it's getting tricky. The functions project has a reference to
Microsoft.Azure.WebJobs.Extensions.Storage (3.0.6)
and that one has a dependency on
WindowsAzure.Storage (9.3.1)
The version difference of 9.3.3 and 9.3.1 leads to the binding problems.
The solution is to either downgrade to 9.3.1 in the referenced project
or
alternatively (and probably recommended): remove WindowsAzure.Storage from the referenced project and replace it with Microsoft.Azure.Cosmos.Table which also contains TableEntity. Important do NOT confuse this with Microsoft.Azure.CosmosDB.Table (notice the "DB") which is being deprecated. Unfortunately, the comments for WindowsAzure.Storage (9.3.3) tell us to change to exactly that incorrect package.
Concusion: it's a hot mess :-)

I had similar problems, I got this when I tried to start my Azure Function V3:
Error indexing method 'Function' Cannot bind parameter 'Table' to type CloudTable. 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.).
As stated, I saw in my project that the WindowsAzure.Storage had a warning sign and stated that it is deprecated.
The fix for me to get my project listening on Table Storage events was to change the using. Apparently I already got a reference to Cosmos in my project using the Microsoft.Azure.WebJobs.Extensions.Storage
Fixing the issue for me by removing the using: using Microsoft.WindowsAzure.Storage.Table; and just replace it with using Microsoft.Azure.Cosmos.Table;
But be aware if you are using the ObjectFlattenerRecomposer.Core it is still using Microsoft.WindowsAzure.Storage.Table and will not work with Microsoft.Azure.Cosmos.Table yet. I have contacted the developer regarding this.

Related

Handling conditional package references in code and unit tests

I have a library project that extends some functionality on EntityFrameworkCore. I'm looking to support both 2.* and 3.*. My project is setup like so:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
[...]
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
</ItemGroup>
[...]
</PropertyGroup>
</Project>
In the code I'm using the function EntityTypeExtensions.FindProperty(...). The signature of this function changes between 2.2.6 and 3.0.0.
The project's code (incorrectly?) uses the signature for 2.2.6. This compiles properly (which shouldn't be the case?) in both target frameworks.
I have a unit test project that multi-targets and has conditional references, much like the original project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;netcoreapp2.0</TargetFrameworks>
[...]
</PropertyGroup>
[...]
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.6" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.0.0" />
</ItemGroup>
[...]
</Project>
All unit tests (incorrectly?) pass in both target frameworks.
Note that even though it builds and tests pass, when the library is used in a netcore3 project (which references efcore 3.0.0 directly) it throws the following exception. Which seems completely reasonable, I just don't understand why it allowed me to get to this point.
System.MissingMethodException: Method not found: 'Microsoft.EntityFrameworkCore.Metadata.IProperty Microsoft.EntityFrameworkCore.EntityTypeExtensions.FindProperty(Microsoft.EntityFrameworkCore.Metadata.IEntityType, System.Reflection.PropertyInfo)'.
Questions:
Is there a way around this so it gets picked up as an error/warning/something, at least, during the build?
Is the solution to this to use preprocessor directives around the call to .FindProperty(...) and based on the framework make the correct method call? Isn't there a way to do this based on the version of efcore instead of the dependency?
Is there a way to unit test this properly with the different packages? Right now as it is, I expected the unit tests to fail in one of the versions since the method does not exist.
Source repository and specifically the call to FindProperty can be found here.
Sample netcore3 project that results in a MissingMethodException when calling the library can be found here.
Stack trace of the exception can be found here.
I have good news and bad news. The good news is that the problem is with your package, and everything works just how you appear to believe it should work. The bad news is I don't know how your package got incorrectly authored.
Steps to verify:
Download Panner.Order version 1.1.0 from nuget.org (you've published 1.1.1 since asking this questions, which has the same, but different, problem). If you have NuGet Package Explorer installed, open the nupkg with that, expand the lib/ folder and double click each of the .dll files. Alternatively you can extract the nupkg as a zip file then use ILSpy or ILDasm or whatever else you want to inspect the assemblies. Notice that both the netstanard2.0 and netcoreapp3.0 assemblies have the same assembly references. In particular the Microsoft.EntityFrameworkCore.dll reference is for version 2.2.6.0, even though we'd expect the netcoreapp3.0 version to use version 3.0.0.0. Therefore I conclude that your netstandard2.0 assembly was copied incorrectly into the netcoreapp3.0 folder of your package. Your 1.1.1 package has the opposite problem. Both the netstandard2.0 and netcoreapp3.0 folders contain the netcoreapp3.0 assembly, so your package doesn't work with projects that try to use the netstandard2.0 assembly.
However, I have no idea why this happens. When I clone your repo and run dotnet pack and check the generated nupkg, I can see that the netstandard2.0 and netcoreapp3.0 assemblies have different references, so I'm confident that the package I generated locally should work. You need to investigate why the packages you publish are not being generated correctly.
To quickly answer your questions:
Is there a way around this so it gets picked up as an error/warning/something, at least, during the build?
It will, as the problem was not with the project, but with the package. If you multi-target your project and call an API that does not exist in at least one of the TFMs, you will get a compile error.
Is the solution to this to use preprocessor directives around the call to .FindProperty(...) and based on the framework make the correct method call? Isn't there a way to do this based on the version of efcore instead of the dependency?
When you call APIs that are different in different TFMs, yes, you can use #if to change your code per project TFM, as described in ASP.NET Core's docs when migrating to 3.0.
I'm going to ignore the "based on the version of efcore" because I'm a detail oriented person, and I don't want to write one thousand words for something that ultimately doesn't matter. The key is that in this scenario, you don't need to. You used conditions on your package references to bring in a different version of efcore per project TFM, so each time your project gets compiled, it's using a different version of efcore, but only one version per compile target. Therefore you don't need runtime selection of different versions of efcore.
Is there a way to unit test this properly with the different packages? Right now as it is, I expected the unit tests to fail in one of the versions since the method does not exist.
You multi-target your test project, but I see you've done that already. Since you're using a project reference, the test won't detect package authoring problems like what's happening.
If you really want to test the package, rather than your code, you could use a nuget.config file to add a local folder as a package source, then your multi-targeting test project references the package, not the project. You'd probably want to also use the nuget.config file to set the globalPackagesFolder to something that's in .gitignore because NuGet considers packages to be immutable and if a debug version of your package gets into your user profile global packages folder, every project you use on that machine (that uses your user profile global packages folder) will use that debug version, making it more difficult for you to make updates. For customers who want to test packages, rather than projects, I highly recommend using SemVer2's pre-release labels and create a unique package version for every single build to reduce the risk of testing a different version than you intend.
Using package reference rather than project reference is a pain, because it's no longer as simple as writing code and then running the test. You'll need to change code, compile the project that gets generated into a package, copy the package into the package source folder if you haven't automated that, update the package version in your test project, then compile and run the test project. I think you're better off keeping the project reference. Fix the package authoring problem and then trust the tooling works.
Not to directly answer all questions above one by one, just to describe the cause of the original issue and some suggestions.
In the code I'm using the function
EntityTypeExtensions.FindProperty(...). The signature of this function
changes between 2.2.6 and 3.0.0.
According to your description, I assume you may use code like EntityTypeExtensions.FindProperty(entityType, propertyInfo); in your original project.
For Microsoft.EntityFrameworkCore 2.2:
FindProperty (this Microsoft.EntityFrameworkCore.Metadata.IEntityType entityType, System.Reflection.PropertyInfo propertyInfo); second parameter=>PropertyInfo
For Microsoft.EntityFrameworkCore 3.0:
FindProperty (this Microsoft.EntityFrameworkCore.Metadata.IEntityType entityType, System.Reflection.MemberInfo memberInfo); second parameter=>MemberInfo
However, please check PropertyInfo Class, you'll find:
Inheritance: Object->MemberInfo->PropertyInfo
And I think that's the reason why the project's code uses the signature for 2.2.6 but it compiles properly in both target frameworks. And it's the cause of other strange behaviors you met after that...
So for this issue, you could use the signature for 3.0.0(MemberInfo) in code instead of 2.2.6(PropertyInfo) to do the test. I think the build will fall as you expected. And as Heretic suggests in comment, for multi-target project, use #if is a good choice.
Hope all above makes some help and if I misunderstand anything, please feel free to correct me :)

Avoiding or fixing namespace pollution in .Net Core

Summary
For my CS capstone project we are encountering an issue with a class name existing in two different dependencies. Specifically, we are using a dependency for using MySQL with Entity Frame and one for just connected and executing MySQL queries directly.
Background
The non-EF is owned by a component outside of the project, and this database is one of our main ways of interacting with the database. It has been requested by the client/mentor that any additions or changes we need be made to a separate database, which is the database EF is connecting to.
The question
My question is essentially about how do I fix error the type <class-name> exists in both..., but I'm more wondering about the root problem of namespace pollution in .Net Core and the courses of action we can take. I have looked into the error and the initial results described a fix that is only applicable in .Net not .Net Core and an explanation that .Net Core does not support aliasing.
Potential fixes
Separate projects - I have asked someone I know who has more experience with .Net, and he suggest making separate projects. While that would obviously work in terms of getting rid of a build error, I do not know how we could make use of one in the main ASP.Net app. I am assuming either both need to be apps or making one into a library. I am also assuming that if it is a separate library it will have the same problem we are having now.
Removing one dependency - I am currently considering that the less than ideal solution is rewriting the code that relies on EF to use the direct MySQL connection dependency. There is less code relying on that EF database, so it would be simpler to rewrite that and some SQL.
Aliasing or full reference - The results I have found that seem to only be applicable to .Net describe using an alias or referencing the full path of the decency in the type. From what I have read, this is not currently supported in .Net Core. If it is, how may I go about it?
using System;
using System.Collections.Generic;
using MySql.Data.MySqlClient;
namespace OVD.API.GuacamoleDatabaseConnectors
{
public class GuacamoleDatabaseConnector : IDisposable
{
private MySqlConnection connection;
...
The error is on the MySqlConnection type and is, in full: GuacamoleDatabaseConnectors/GuacamoleDatabaseConnector.cs(81,16): error CS0433: The type 'MySqlConnection' exists in both 'MySql.Data, Version=8.0.15.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' and 'MySqlConnector, Version=0.49.2.0, Culture=neutral, PublicKeyToken=d33d3e53aa5f8c92' [/Users/markbeussink/Action/OVD/OVD.API/OVD.API.csproj]
Here is the .cs.proj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App"/>
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All"/>
<PackageReference Include="Ldap.NETStandard" Version="1.0.3"/>
<PackageReference Include="MySql.Data" Version="8.0.15"/>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0"/>
</ItemGroup>
</Project>
Just create a new project "class library" and inside this project, you can create an interface which gives you access to a method from one of your component (you need to implement your "component" and its method inside this project). Something like in facade pattern. Then in the rest of your solution, you will use a newly created project reference only. This solution allows you define your own namespace name
It's really bad form for two separate projects to have a type with the same namespace and the same name, for the reason you've just discovered. It is not at all normal or expected that you would run into such a conflict, and you may well never encounter it again in your career.
It looks like this project:
https://www.nuget.org/packages/MySqlConnector/
decided to clobber the namespace of the more official ADO.NET provider for MySQL:
https://www.nuget.org/packages/MySql.Data
by defining a type called: MySql.Data.MySqlClient.MySqlConnection, instead of using MySqlConnector.MySqlClient.MySqlConnection, or somesuch.
The best way forward is to exclude one of these from your projects, and use just the other. Here the obvious choice would be to switch from
https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql/
to
https://www.nuget.org/packages/MySql.Data.EntityFrameworkCore/
But I don't have any opinion on the relative merits of these libraries.
If you can't do this, C# provides a compiler directive for you to alias one of the assemblies with a different namespace. See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0433
This will in effect add a new outermost namespace level to the offending assembly, so the other MySqlConnection would be known (only in your code) as SomeAlias.MySql.Data.MySqlClient.MySqlConnection.

WCF WebService with warnings and InvalidOperationException

I am currently trying to connect my ASP-NET Core 2 application to Magento's API (WSDL v2), but keep receiving the following errors:
*Doesn't matter which method I call, even the new PortTypeClient().loginAsync(username, password); throws that, with this random endpoint name salesOrderShipmentAddComment.
InvalidOperationException: The operation
'salesOrderShipmentAddComment' could not be loaded because it
specifies \"rpc-style\" in \"literal\" mode, but uses message contract
types or the System.ServiceModel.Channels.Message. This combination is
disallowed -- specify a different value for style or use parameters
other than message contract types or
System.ServiceModel.Channels.Message.
However, using SoapUI, postman or importing with framework 4.6, it works perfectly.
Using the Magento v1 API it works too, but I don't want to use this version.
During the import in asp-net core, I also recieve those warnings (importing v1 doesn't shows any warning):
I'm almost creating a new 4.6 application, hosting it separately to work as a bridge between my application and Magento, even if it hurts my performance and architeture.
This is how I'm doing the import:
*Obs: In Data Type Options, I also tried checking different options, and selecting other data types.
Anything would help...
Thanks in advance
I had the same problem. Make sure you update your Nuget Packages to 4.5.3. After, works correctly for me.
Indeed updating the following packages to version 4.5.3 seems to resolve the issue:
System.ServiceModel.Duplex
System.ServiceModel.Http
System.ServiceModel.NetTcp
System.ServiceModel.Security
Seems like 4.4.4 version of those packages are installed by default, while adding WCF service reference via VS 2017 15.9.4 UI
Just update System.ServiceModel.Http to 4.5.3
According to
https://ozguradem.net/english/coding/2018/11/06/soap-services-with-dotnet-core/
Open .csproj file and edit following packages minimum version like these
<ItemGroup>
<PackageReference Include="System.ServiceModel.Duplex" Version="4.5.*" />
<PackageReference Include="System.ServiceModel.Http" Version="4.5.*" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.5.*" />
<PackageReference Include="System.ServiceModel.Security" Version="4.5.*" />
</ItemGroup>

What causes a mismatch in a .net core nuget package that contains an abstract class requiring a dictionary

I've setup a nuget package (https://www.nuget.org/packages/AlexaCore/) that gets created via dotnet pack with parameters /p:Version=%system.build.number% driven off a TeamCity variable.
When I reference the package in another .netcore1.0 application and create a new AlexaIntent Visual Studio 2017 doesn't persist the correct parameters on the GetResponseInternal method. It should be: Dictionary<string, Slot> but defaults to GetResponseInternal(System.Collections.Generic.Dictionary slots)
If I then correct the signature Visual Studio indicates the class doesn't correctly implement the base class:
Why might this be? Is the generation step invalid or somehow missing required settings.
FYI the Slot class exists in another package: Alexa.Net (https://github.com/timheuer/alexa-skills-dotnet/tree/master/Alexa.NET) which should be referenced by the nuget definition in my projects csproj file:
<ItemGroup>
<PackageReference Include="Alexa.NET" Version="1.0.2" />
<PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
</ItemGroup>
If I reference the class library without nuget (ie via a project in the same solution) then the issue is not visible.
Since updating to the latest version of Resharper (2017.2) this issue is no longer visible. I'd suggest doing the same.

Unable to declare an ArrayList using Code on OSX

I'm using Code on OSX together with the .NET Core. While trying to create an ArrayList I'm getting an error that the namespace cannot be found.
The System.Collections is used already. While examining what is suggested from System.Collections I see that not all of the methods are listed as in the documentation.
What could be the problem? I installed the latest .NET Core from MS site.
You cannot use the type because it is defined in a separate NuGet package,
http://www.nuget.org/packages/System.Collections.NonGeneric/
Note that only a few platforms are supported by this package, so for some monikers, you cannot reference it.
The recommended approach is to switch to the generic version of the collection types.
Looks like System.Collections.NonGeneric is not supported in Mac. It didn't work for me even though I had that package installed. Looks like it's deprecated and also Microsoft suggests that to use Generic lists instead.
Open you .csproj and add the following under
<ItemGroup>
<PackageReference Include="System.Collections.NonGeneric" Version="4.3.0">
</PackageReference>
</ItemGroup>
in the terminal or command prompt, make sure you are on the same working directory as your project and run
# dotnet restore
You can now use it in your project

Categories

Resources