As of 0.5.4 check-in, the Breeze.Sharp/DataService.cs::InitializeHttpClient method creates an HttpClient with the default constructor. My intranet breeze web api service has a .Net console application, which needs to be authenticated by the service using Windows authentication. In a pre-breeze universe, I would have created an HttpClient object that takes the following HttpClientHandler in the constructor, which would then send the user's credentials along with the http request:
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true
};
So the request here is to be able inject my own HttpClient into the DataService, or otherwise specify this setting when I construct an EntityManager.
For now, I have resolved the issue by modifying my own instance of the Breeze.Sharp library by updating the DataService constructor to optionally take in an HttpClientHandler, like so:
public DataService(String serviceName, HttpClientHandler handler = null) { ... }
I would prefer to keep using the main library so hopefully this issue gets tracked and resolved for everyone else. :)
Updated 6/3/2014
This is now supported in Breeze 0.5.5, available now
Previous post
This makes sense, I'll try to look into it before the new release. ... and thanks for the input.
Thanks Jay, I have integrated release 5.5 into my project and no longer need a private build. :)
Related
I'm working on a corporate ASP.NET Core application that needs to reach out to a cloud resource (Elastic APM).
Unfortunately, our corporate proxy is swatting down the request before it can complete. It's not my code that making the requests but code within a NuGet package, so I can't easily change how it's making the connection.
I'm hoping to use middleware to inject the proxy details before it goes out the door. I've tried this below, but it doesn't seem to be working:
services.AddHttpClient<HttpClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
{
Proxy = new WebProxy(new Uri("http://proxy.mycompany.com:8080"), true, new string[]{}, CredentialCache.DefaultCredentials)
});
Long-term, I am going to whitelist the cloud resource. But as I prototype this solution, I'd prefer not to go through that red tape...
I am experiencing some interesting behavior with the HttpClient from the .NET Framework (4.5.1+, 4.6.1 and 4.7.2). I have proposed some changes in a project at work to not dispose of the HttpClient on each use because of the known issue with high TCP port usage, see https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/.
I have investigated the changes to check that things were working as expected and found that we are still experiencing the same TIME_WAIT ports as before.
To confirm that my proposed changes were correct I have added some extra tracing to the application that confirm that I am using the same instance of the HttpClient through out the application. I have since used simple test application (taken from the aspnetmonsters site linked above.
using System;
using System.Net.Http;
namespace ConsoleApplication
{
public class Program
{
private static HttpClientHandler { UseDefaultCredentials = true };
private static HttpClient Client = new HttpClient(handler);
public static async Task Main(string[] args)
{
Console.WriteLine("Starting connections");
for(int i = 0; i<10; i++)
{
var result = await Client.GetAsync("http://localhost:51000");
Console.WriteLine(result.StatusCode);
}
Console.WriteLine("Connections done");
Console.ReadLine();
}
}
}
The issue only occurs when connecting to a site that is hosted in IIS using Windows Authentication. I can reproduce the issue easily by setting the Authentication to Anonymous (problem goes away) and back to Windows Authentication (problem reoccurs).
The issue with Windows Authentication does not seem to be limited to the scope of the provider. It has the same issue if you us Negotiate or NTLM. Also the issue occurs if the machine is just a workstation or part of a domain.
Out of interest I created a dotnet core 2.1.0 console app and the issue is not present at all and works as expected.
TLDR: Does any one have any idea on how to fix this, or is it likely to be a bug?
Short version
Use .NET Core 2.1 if you want to reuse connections with NTLM authentication
Long version
I was quite surprised to see that the "old" HttpClient does use a different connection for each request when NTLM authentication is used. This isn't a bug - before .NET Core 2.1 HttpClient would use HttpWebRequest which closes the connection after every NTLM authenticated call.
This is described in the documentation of the HttpWebRequest.UnsafeAuthenticatedConnectionSharing property which can be used to enable sharing of the connection :
The default value for this property is false, which causes the current connection to be closed after a request is completed. Your application must go through the authentication sequence every time it issues a new request.
If this property is set to true, the connection used to retrieve the response remains open after the authentication has been performed. In this case, other requests that have this property set to true may use the connection without re-authenticating.
The risk is that :
If a connection has been authenticated for user A, user B may reuse A's connection; user B's request is fulfilled based on the credentials of user A.
If one understands the risks, and the application doesn't use impersonation, one could configure HttpClient with a WebRequestHandler and set the UnsafeAuthenticatedConnectionSharing, eg :
HttpClient _client;
public void InitTheClient()
{
var handler=new WebRequestHandler
{
UseDefaultCredentials=true,
UnsafeAuthenticatedConnectionSharing =true
};
_client=new HttpClient(handler);
}
WebRequestHandler doesn't expose the HttpWebRequest.ConnectionGroupName that would allow to group connections eg by ID, so it can't handle impersonation.
.NET Core 2.1
HttpClient was rewritten in .NET Core 2.1 and implements all the HTTP, networking functionality using sockets, minimal allocations, connection pooling etc. It also handles the NTLM challenge/response flow separatelly so the same socket connection can be used to serve different authenticated requests.
If anyone is interested, you can chase the calls from HttpClient to SocketsHttpHanlder to HttpConnectionPoolManager , HttpConnectionPool, HttpConnection, AuthenticationHelper.NtAuth and then back to HttpConnection to send the raw bytes.
I've written a C# app that performs web requests via the System.Net.Http.HttpClient (e.g. client.GetAsync(uri);). Compiling and executing it with the .Net runtime, all these calls are successful. However, compiling and running with Mono, they fail with exceptions ("IOException Authentication or decryption failed").
However, switching to a network that doesn't go through the proxy resolves the issue. So in conclusion, it's not a certificate or whatever issue, but just the issue of the proxy.
Same applies for the tlstest tool: Fails miserably with the proxy, works fine without it.
How do I configure mono to use the proxy settings / use the system proxy settings?
Can you try setting the proxy in HttpClient? You can set proxy credentials if necessary.
WebProxy proxy = new WebProxy("proxyaddress", port);
HttpClientHandler handler = new HttpClientHandler()
{
Proxy = proxy
};
HttpClient client = new HttpClient(handler);
Try to use modernhttpclient component. This library brings the latest platform-specific networking libraries to Xamarin applications via a custom HttpClient handler which can handle for you this kind of issues.
I'm using Microsoft HTTP Client Libraries - PCL (installed via NuGet) to communicate with a public REST API. Because I'm behind a corporate firewall, I need to configure the proxy info on the HttpClientHandler.
However, when setting proxy on the HttpClientHandler, it throws the following error:
Method not found: 'Void System.Net.Http.HttpClientHandler.set_Proxy(System.Net.IWebProxy)'.
There's nothing special about my code, so I am a bit puzzled:
var handler = new HttpClientHandler
{
UseDefaultCredentials = false,
Proxy = new DefaultProxy
{
Credentials =
new NetworkCredential(
"firstname.lastname",
"P4ssw0rd",
"DOMAIN")
},
UseProxy = true
};
this.client = new HttpClient(handler);
Some notes:
I've successfully used the HttpClientHandler from the standard .Net library (i.e. not PCL) for another project, so I know the proxy information is correct.
I've successfully retrieved the data when the proxy is bypassed (i.e. outside the corporate network, or no proxy).
DefaultProxy implements IWebProxy.
This error is due to the HttpClient package not being installed on the consuming project. You should be getting a warning similar:
All projects referencing [consuming project] must install nuget package Microsoft.Bcl.Build.
Basically, every referencing a class library that references HttpClient & Async must also reference HttpClient & Async.
I am very new to web service stuff so please be kind.
I have written a simple POJO class, and deployed it on an axis2 server:
public class Database {
private Project project;
public void login(){
project = new Project();
project.setDescription("Hello there");
project.setName("To me");
}
public Project getProject(){
return project;
}
}
I call the service from a c# client:
localhost.Database db = new WindowsFormsApplication1.localhost.Database();
db.login();
localhost.getProjectResponse pr = new WindowsFormsApplication1.localhost.getProjectResponse();
pr = db.getProject();
When I debug the response is null.
At the java end, when I call getProject, the project object is null.
What's happening?
How do I preserve the state of project between service calls?
For most toolkits, web services are stateless by default. I think axis is no different.
If you want to maintain state between calls then you will need to enable sessions. An example on how to maintain sessions in axis can be found at:
http://kickjava.com/src/test/session/TestSimpleSession.java.htm
On the .NET side you will need to assign a CookieContainer to your request to store the session identifier. See HOW TO: Use CookieContainer to Maintain a State in Web Services for more information.
I think your code would look something like this:
localhost.Database db = new WindowsFormsApplication1.localhost.Database();
// Assign the CookieContainer to the proxy class.
db.CookieContainer = new System.Net.CookieContainer();
db.login();
localhost.getProjectResponse pr = new WindowsFormsApplication1.localhost.getProjectResponse();
pr.CookieContainer = db.CookieContainer;
pr = db.getProject();
I think that should let you do what you want -- but I wouldn't recommend it.
Designing service interfaces is a bit different than designing object oriented interfaces. Service interfaces typically eschew the use of state and instead require the consumer to provide all of the relevant information in the request.
From Service-Oriented Architecture:
Services should be independent,
self-contained requests, which do not
require information or state from one
request to another when implemented.
I would definitely recommend reading that article and perhaps revisiting your design.
I'm not sure why #shivaspk left a comment instead of writing an answer, it is quite correct: web service calls (not just axis calls) are meant to be stateless, so although the project object gets created by
db.login();
when you call
db.getProject();
It is being called on a different instance of your Database class that was created by Axis to service the second call.
There is no really good answer to your question, except for you to rethink what you are trying to do. If you need some kind of authentication (via login), then that authentication needs to be part of every web service call.