Ambiguous routing exception in gRPC .NET 5 / C# project - c#

I've created my 1st gRPC App in .NET5, using Grpc.AspNetCore and protobuf-net nugets.
Initially all my service methods were synchronous. At this stage client-server communication functioned well.
Then I found that I need async support too, and added an async equivalent for each existing method, like:
AssemblyNamesDto GetAssemblyNamesFromFiles(MyDto payload);
Task<AssemblyNamesDto> GetAssemblyNamesFromFilesAsync(MyDto payload);
Since I've done this I get Exceptions on the server side with the message:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.
If I rename the Async "overload" to something like GetAssemblyNamesFromFiles2Async, the AmbiguousMatchException goes away.
So my assumption is that there is generated code somewhere that makes pairs of synchronous and asynchronous method names implicitly.
Adding "Async" at the the end of the synchronous method name and vice versa.
I've seen this in WCF-REST projects that method pairs like this are are generated automatically.
So my question is: if the async methods are generated automatically, how can I use them?
I can't find generated code files in the project.
Or: how can I somehow solve the routing ambiguity issue by e.g. adding [Route] attributes or by other means?
I used the gRPC project template of VS 2019.
I didn't add any routing attributes. The service just implements the service interface methods, which have no overloads with same name.
The project is not ASP.NET MVC.

Related

gRPC Service use models from library

I am working on my first gRPC service. I have everything working. As in, I can call my service from the client and get a response. My question is can my gRPC service use models from another library?
I have several projects in my solution.
gRPC Server
gRPC Client
Common DTO Library
And a Few more
When I define my proto file is it possible to use the classes from the Common DTO Library?
my.proto
syntax = "proto3";
option csharp_namespace = "myNameSpace";
package myPackageName;
// The service definition.
service MyService{
rpc MyMethodName (DtoFromAnotherLibrary) returns (byte[]);
}
Thank you,
Travis
That's not possible because Proto does not know about your C# projects.
You may consider using code-first gRPC though, where you write C# code that is then creating your proto.
As #Ray stated, you cannot use your model objects through the gRPC interface and he provided a link to the code-first method.
I tend to think of my proto definitions as my external interface and update them with care to ensure backwards compatibility as the interface ages. Because of that, I will code up model objects separate from the gRPC definitions and write extension methods (ToProto for the model, ToModel for the gRPC message) to go back and forth between the two types. It may seem like duplicated effort, but having the flexibility to add things to my model objects like property change notifications, or other convenience methods/properties without affecting the external interface is a plus to me. I spend a lot of time working on the front end, so it analogous to the model/view model relationship.

Implementing GraphQL in MVC solution - Never returns

I have added a few classes to send requests and handle responses from an external GraphQL web API, which use the GraphQL package from NuGet as well as HttpClient to connect to the API. The classes live in one project of my solution ("providers"). I have also added Test classes and methods to test the functionality of the service classes. The Tests all work as expected - results come back and they match the same queries made in Postman. Having success with the tests, I added references to the service classes to the main project which is an MVC web application in order to supplement user search capabilities - so calling a method from the same project as the Api helper classes within a controller in the MVC application. This is when I started having issues.
As an aside I did not have to add any of the GraphQL packages to the Test project, and it was able to work fine by just referencing the provider project that contains the api helper class. So it seems a bit like overkill in the first place that I had to add all that to the MVC project.
Initially, I was getting errors such as "ReadAsAsync doesn't exist" (this is a method of the System.Net.Http.HttpContent class I think?). This method was used in other classes that consume other external web services using HttpClient in the same project. In fact the method that was failing was nearly identical to ones in other classes that had been working for years at this point. So I thought it was strange it stopped working at this time. I eventually concluded it had something to do with all the dependencies added by adding the GraphQL nuget packages to the "providers" project.
I then added those same GraphQL packages to the MVC project to see if that resolved the issue. This added some issues where it couldn't find some System.IO libraries. I had seen this before in another project where I had to update the .NET version and the solution in that case was to remove the offending dependentAssembly entries in the web.config file. I did that here. Now, I load the web application in debug mode, and can click through to the page where the controller action to search using the new API class is located. The original search actions still work - I am able to get results using them. But the new API method does not. It does not throw an exception. It does not return results. The execution simply stops or seems to stop after the call to the API happens. The GraphQLHttpClient.SendQueryAsync just never comes back. It could just be that I'm not waiting long enough, but I gave it 10 minutes at one point for a query that runs in seconds in the test project, and also in seconds in postman. The application remains operational, though. I can still use other functions of the site after clicking on this.
I guess the question is - how can I find out what the problem is here? Or correct it in some way? I'm currently trying removing different dependentAssembly entries in the MVC project but that isn't really working out very well so far. Some of those entries are needed by the application. But not all of them.
** UPDATE **
I was able to work with some people on another site to resolve the issue.
Basically I was calling:
public static GqlResponse GetGqlResponse(string name){
var gqlResponse = client.SendQueryAsync<GqlData>(gqlRequest).Result;
return gqlResponse;
}
In a method in a class in one project, from an MVC controller action in a different project. Because of this, it caused a deadlock.
public ActionResult Index (){
var gql = myotherproject.myclass.GetGqlResponse("moo");
return View(gql);
}
The solution to this issue was to not try to make an asynchronous process completely synchronous. I changed the whole code pathway to be asynchronous.
public class MyGplClass{
public static async Task<GplResponse> GetGplResponse(string name){
// build the request, client, etc...
var gqlResponse = await client.SendQueryAsync<GqlData>(gqlRequest).ConfigureAwait(false);
// process response...
return gplResponse;
}
}
And in the MVC project:
public class MyController : BaseController{
public async Task<ActionResult> Index(){
var gqlr = await project2.MyGplClass.GetGplResponse("moo");
return View(gplr);
}
}
To reference for the future, hopefully this link stays alive: Don't Block on Async Code. But the gist of it is that because I was using the .Result property of the Task object created by calling the Async method, this was causing a deadlock within my Web Application (ASP.NET, .NET Framework), because of the way these sorts of web applications work. Because normally this problem had not happened for me, I was unprepared for it and I did not know what was happening when it happened this time. Hopefully this solution helps some people who have a similar problem as I stated in my question.

How to upload files to HttpRequest

I'm making with VS2015, WPF and C# a test application in which we can test and debug an ASP.Net web service application.
Both projects belong to the same solution.
Because some methods in the webservice would normaly called by an URL including some parameters i had to create the HttpRequest programatically before calling such methods.
In one of these cases it is necessary to add files to the request.
Fortunately i have found in this forum the following thread:
How to create a file to populate HttpContext.Current.Request.Files?
The version from StuartLC seemed to be very practical but i have a little problem with the calling of InvokeMethod.
The objects which use InvokeMethod (types object and HttpFileCollection) do normally not have that method.
Have i forgotten some references or assemblies in my test project?

ASP .Net Core Dto's and Controllers to typescript classes & interfaces

My idea consists of two main elements:
Take C# Dto's (Data-tranfer-objects) and convert them into typescript interfaces to ensure client-side models are in sync with server side.
Take ASP .Net core controller endpoints and convert them to typescript classes that uses a http-service or similar. Again, to ensure client-side requests are in sync with the server.
And whenever a change have been made to a controller or dto, the typescript generated items should then refresh to stay in sync while developing.
I have done some research and found the following Stack Overflow threads and other sources:
DTO to TypeScript generator which suggest using the TypeLite library, which seems great, but according to the documentation, this either requires a [TsClass] Attribute or a reference to class on startup. But, since the project structure I'm using is setup so that all dto's is located in a *.Dtos namespace, I'm kinda missing a TypeScript.Definitions().ForNameSpace(). Also, this only solves the first idea/problem.
Swashbuckly.AspNetCore Would allow me to generate swagger documentation from both the controllers and dto's, and then the task would be to someway interpret the swagger documentation and create typescript classes and interfaces from that. The cons is that as far as i can read, this requires me to startup the server, which if possible i would like to avoid since it would make it hard to update on file change.
FYI, this is a new project I'm about to start, so there's no legacy code to update, also, all of the ASP .NET Core endpoints will return IActionResult to enable the return of Ok(), BadRequest() and so on. So to get the return model would in my mind be hard, since there's not an easy way to get the dto it produces, if any.
So, i have thought of the following solutions that solves both problems:
Create a separate package/application that uses the Swashbuckly lib and generates the models and controllers without starting up the whole server.
Create annotations on every endpoint, something along the lines of [Produces(SomeDto)], where after i would create a small console-application that uses reflection to get information and generate typescript from that. This would of cause requires developers to keep this information in sync, so in my mind there's kinda duplicate information.
But, both of these solutions would not auto-update on C# source file save.
Looking forward to any discussions/suggestions.
Considering your first point, I made a C# DTO to typescript interface generator that uses MSBUILD tasks so its completely independent of your workflow. It also just does it from the source which makes it a bit less stable but you don't have to make any template files.
Find it here or just search for MTT on nuget
In case you are still looking.... I think Typewriter http://frhagn.github.io/Typewriter/ is your solution. You can generate templates specifying what and how to transform.
It doesn't meet all of my needs only because I need a tool to dynamically generate a complicated folder structure, but that's coming in their v2 roadmap.
Besides that, it does a lot of heavy lifting and is pretty easy to configure.

Calling an OData Service Operation from Linqpad

Does anyone know if its possible and if so, what the syntax is for calling a service operation via linqpad?
Also, can I used named parameters when I call it using linqpad- how? That would be great b/c I have a lot of parameters in the service operation and I don't want to have to specify each one.
Thanks!
Unfortunately, this is not possible: LINQPad relies on the .NET WCF client and EntityClassGenerator in System.Data.Services.Design.dll, which don't really support service operations (as of Framework 4.0).
The workaround at this stage is the same as what you'd do if you were coding in Visual Studio and is described well here.
Hence you could type the following into LINQPad to call the operation GetContacts(string firstName):
this.Execute<Contact> (new Uri ("GetContacts?firstName='John'", UriKind.Relative))
or, if the service returns a sequence of objects:
CreateQuery<Contact>("GetContacts").AddQueryOption("firstName", "'John'")

Categories

Resources