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.
Related
My team is building an API which interfaces with another API with many endpoints. Our app is in .net core, so we've been using the connected services wizard for each reference. This means we had to specify the URI's for our endpoints.
Everything is working as expected, but when we move out of dev/qa to staging, all of those references will be wrong, and I will have to manually switch the connected service url's (I think I can do this by simply accessing the ConnectedService.json for each reference and changing extended data: inputs: "[url]" to the different url, but that would mean changing ~20 (so far) references every time we change environments.
My boss says it will become unmanageable as the scope widens. Is there a way to implement dependency injection for service reference uri's so that when the env changes, I can change the reference automatically in code? (I will have the references base url saved in appsettings.json so we can change it without recompiling, because the base url is shared by all of the services, and the wsdl name at the end of it stays the same for each reference across environments.)
The reason I'm asking this as a new question is because, for one, there is limited help on the .net core implementation of service references with the wizard. Most solutions I've found are from 10-15 years ago and it took me a day to realize that those solutions don't apply. An example of a relevant solution is found here: Changing WCF Reference Url .Net Core, however, I don't understand the proposed solution at all.
In the solution, the OP says that adding the code var client = new GetUrlContractClient(new BasicHttpBinding(), new Endpoint("https://someurl/v3/GetUrl-Prod.svc"); solved the problem of updating the uri. My question is, where does this code live, and what is this client object? When I make a call to the API we're referencing, I create a new object asynchronously, there is no reference to some pre existing variable like client above... Did we already have to implement this somewhere and I'm just not seeing it? And what even is this GetUrlContractClient that is being called? I don't understand where the OP is using this if they set up the reference using the wizard.
[Edit] I should say that I also found that implementing the partial method "ConfigureEndpoint" to extend the auto generated code is the "preferred solution," as seen here load WCF service by environment in .net core project. When I try my best to do this for one of the references, it throws a security exception. If this is the way to do it, then I will devote my time to solving that error. However, this solution involves extending the ConfigureEndpoint for every reference, so I would have to do it upwards of 15 times, so it didn't seem to me that it would be the solution. Maybe this is what the OP for the referenced question was doing, but if so I do not see the connection. They seem to be completely different solutions.
It seems like this would be a relatively straight forward thing to lookup and solve with what we've already implemented, but I have had no luck. Anytime I find something, the answer is vague-ish like above and I don't see how it applies to my situation. How can I change the uri's for my web service references that are set up with the web service reference wizard?
Extending ConfigureEndpoint for each connected service works. The path cannot not include the ?wsdl at the end. The extension code (for one of my files) is below.
public partial class CreateOrderPortTypeClient
{
const string uriSuffix = "(last part of URI without ?wsdl)";
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials)
{
EndpointCreator.SetServiceEndpointAddress(serviceEndpoint, uriSuffix);
}
}
I also added a class EndpointCreator which handles the base address, like so.
public class EndpointCreator
{
static string uriBase;
public static void GenerateBaseAddress(string uriBase)
{
EndpointCreator.uriBase = uriBase;
}
public static void SetServiceEndpointAddress(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, string uriSuffix)
{
serviceEndpoint.Address =
new System.ServiceModel.EndpointAddress(new System.Uri(uriBase + uriSuffix),
new System.ServiceModel.DnsEndpointIdentity(""));
}
}
I assigned the uriBase in startup by accessing the config. While I had to extend each one individually, its actually very manageable because this is a small thing to do when adding a new service through the wizard.
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.
I am having a bit of a terrible time getting a WebAPI 2 setup to work. I am trying to place this within an already existing solution containing multiple projects.
The current layout is (with generalized names):
-Server.Project
-Services.Project
Right now, IIS is doing the hosting. There is an application setup in IIS called Application.
So, right now if you go to localhost/Application/service.asmx , everything spins up and does it's thing. The global.asax.cs file and most of the service classes are in Services.Project, even though Server.Project is the software's entry point.
I want to make use of WebAPI's new things.
I've defined a controller (TestAPIController) in Services.Project, and a configuration file with the default mappings (from all of the examples). The Register() function is called from Application_Start(). I've verified that it is at least being called.
If I go to:
localhost/Application/TestAPI/anything ever, it gives me a 404 error.
I tried to use the Route Debugger by installing the package and going to localhost/Application/rd (also tried /Application/TestAPI/rd). Neither work. I get a 404.
This leads me to believe I have something setup wrong so that the WebAPI stuff is not actually spinning up and hosting correctly.
I have tried doing the OWIN startup as well, but it didn't seem to help.
For that, I just added the appropriate startup class stuff to my web.config, and to my Global class in Services.Project.
I've verified that the Configuration() function for Owin is being called as well, but I still cannot hit the paths I've setup.
I think the fact that the entry point is Server.Project, but the controller/routes are defined in Services.Project might be part of the issue.
However, all of the assemblies are placed in the same bin directory. I was lead to believe this should allow everything to be loaded/found.
Am I missing something?
If anything is not clear, sorry. Let me know so I can clear it up.
Thanks.
EDIT:
So, I got a different route debugger to install and cooperate.
(install-package RouteDebugger).
If I hit my main URL: localhost/application
This route debugger launches and shows that no paths were matched, but it ALSO shows the routing paths that I defined but are not found.
...so now I am even more confused. How are they showing up and obviously known about, but are unable to be reached?
If you followed "typical" WebAPI setup tutorials, you would have defined the custom ApiController route to include "/api".
All of your urls should look like:
localhost/Application/api/TestAPI/anything
As an aside, it might be worth it to just spin up a brand new Web API project. Retrofitting an existing project might cause more headaches than it's worth.
I'm new with Spring but managed to create a DatabaseHelper project using it and others projects in my first solution are calling that helper to execute cruds and all is working fine.
Now I'm creating a second solution, a web service, and in this new solution I'll need to make a couple of selects. I got the "easiest" path and included my DatabaseHelper to the new solution.
Everything compiles fine but at my DatabaseHelper core something go wrong.
at the line:
return (IService)SpringSingulizer.SpringHelper.GetObject(contextName, "ServiceImpl");
Spring is unable to find that ServiceImpl object.
That's strange since it works fine at my first solution. For sure I forgot something or its because web services works another way.
After diggind in a bit I found Spring needs a ResourceModule class to load that SpringServices.xml where Spring can find that ServiceImpl class definition.
For my first solution that is achieved just by declaring that class and putting that class and XML at the project calling the helper.
I'm not sure how to do the same for my web service nor if it the way it's supposed to work.
And my question is how to put my helper to work for my second solution ?
I find the problem after digging deeper and deeper. First problem is there are already another context with another name but returning spring GetObject default object. Second problem was context handling was a bit messed because there are another class build by a coworker trying to create context by itself.
I'm using MVCTurbine in my application which automatically injects my controllers in my asp.net-mvc 2.0 website. My master pages, view pages, css, web.configs and javascript files are in my mvc project, all the rest (including the global.asax) are in seperate libraries.
When I put a breakpoint at my Controller's constructors I notice that ALL the constructors are hit 4 times for each request and the controller with the actual action in gets hit an extra 5th time.
I've tried to reduce the problem surface in the following ways:
Reduced my view and masterpage to minimum (all custom code removed)
Reduced my view
Simplified my controller to the minimum
Simplified my global.asax.cs to minimum
The breakpoint has no meaningfull stacktrace.
Posted the simplified code to http://gist.github.com/514442
The problem code in context of a project can be found at http://github.com/boriscallens/Beek
I'm kind of out of ideas, any hints or ideas on how to continue debugging this are welcome.
I never noticed this before :/ Anyway, after some digging, I found where it calls the constructor 4 times. It's supposed to call them 4 times only once, and cache the results (it's looking for filters), but MvcTurbine seems to be losing the instance with the cache.
This is the class that's causing problems: http://github.com/lozanotek/mvcturbine/blob/master/src/Engine/MvcTurbine.Web/Controllers/DefaultFilterFinder.cs
If you copy & paste this class into your project, and register it in one of your IServiceRegistration classes it works like it's supposed to.
locator.Register<IFilterFinder, FilterFinder>();
(I renamed the class to FilterFinder from DefaultFilterFinder)
UPDATE
I figured out why it doesn't work. It's because when I downloaded the 2.1 version from downloads, the code that caches the results is not there yet. If you download the latest source from http://github.com/lozanotek/mvcturbine, it works (you have to compile the code, not use the binaries in deploy folder).