I am fairly new to Restlet and wrote small piece of code to make a HTTP call. It is working but I was wondering how can I add HTTP Connection pooling (apache) into it.
I am not able to find any tutorial or reference code for it.
Client client = new Client(Protocol.HTTP);
ChallengeResponse challengeResponse = new ChallengeResponse(
ChallengeScheme.HTTP_AZURE_SHAREDKEY,
acctName,
accKey);
String url = RestHelper.createRequestURI("CCC");
Request request = new Request(Method.GET, url);
request.setChallengeResponse(challengeResponse);
Response response = client.handle(request);
Any references or help will be appreciated.
In fact, Restlet internally manages a pool at the client connector level. Configuration of this pool can be done using the context of your client. The following example describes to configure it:
Client client = new Client(new Context(), Protocol.HTTP);
client.getContext().getParameters().add("maxConnectionsPerHost","5");
client.getContext().getParameters().add("maxTotalConnections","5");
You can notice that these parameters depend on the underlying client connector you use.
Here are some helpful links:
Doc related to connectors: http://restlet.com/technical-resources/restlet-framework/guide/2.3/core/base/connectors
Javadoc containing parameters for the HTTP client connector: http://restlet.com/technical-resources/restlet-framework/javadocs/2.3/jse/ext/org/restlet/ext/httpclient/HttpClientHelper.html
Notice that if you use ClientResource, you need to share the same client to have only one instance of the client connector under the hood. Otherwise a new one is instantiated for each request. See the way to implement this below:
Client client = new Client(new Context(), Protocol.HTTP);
ClientResource cr = new ClientResource("http://myurl");
cr.setNext(client);
Hope it helps,
Thierry
Related
I have multitenant Web API application with Hangfire scheduler that calls a task which trying to connect to self endpoint through external server DNS name with tenant name in it. Doing it this way, because Hangfire doesn't have HttpContext to resolve on which tenant task must shoot. On my staging server or if I send this request from Postman it works nice, but on my local machine and on production server it raises the error from title.
The code looks like nothing special:
var url = $"{tenant.Url}/notifications/client/send-appointment-sms";
var jwtToken = await _authService.GetTokenByUsername("admin");
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken.AccessToken);
var response = await _httpClient.SendAsync(requestMessage);
Where tenant.Url is for example https://api.tenant1.example.com/api2 which is available from browser on production server where application is running.
If I understanding clearly, my application can not connect to itself for some reason.
I have tried common solutions like firewall settings or disable proxy, still nothing on this point. What can I check next?
UPD I must add that NodeJS server on production is able to call this service too, so I think issue is not in server but maybe more about ASP.NET configuration settings.
I'm trying to make a very simple service call from VS2012.
The service is on a domain outside a proxy and requires logon credentials.
I have set a refrence to the service in visuals studio. At that point i entered in the remote domian username and password and VS created all the proxy classes for me.
I then added this line to appconf file.
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true">
</defaultProxy>
</system.net>
Which i believe will allow me to get through our proxy using my own credentails
I then wronte this simple piece of code
private void GetData()
{
OASIS.OasisServiceSoapClient o = new OASIS.OasisServiceSoapClient();
o.ClientCredentials.UserName.UserName = #"OtherDimain\UserName";
o.ClientCredentials.UserName.Password = "Password";
var d = o.SelectOfficersAll();
}
and of course it didn't work and i got all the errors that everyone has posted on.
So first question is
do i need to add this
o.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
because i did and still get that same stupid error
"The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'."
and inner exception
"{"The remote server returned an error: (401) Unauthorized."}"
so am i getting through the proxy ?
Am i using my own credentials ?
Am i passing the right paramaters in to the Service Model ?
Some examples show the username and password properties in the code above are to impersonate the current job.
But i read these on the MSDN page as being the credentials you want to use on the remote serve. The Help topic is ambigious. And if i don't enter them here then how ?
I'm trying to do something so simple , yet can't seem to get past this point.
Ok thanks to my Colleague Sean. It seems that depending on wether you are calling a web service or a WCF services determines what you need to do.
So as a web service this works
OASISWeb.OasisService s = new OASISWeb.OasisService();
s.Credentials = new System.Net.NetworkCredential("Username", "Password", "Domain");
var d = s.SelectOfficersAll();
DataSet x = (DataSet)d;
if it's a WCF service then you need this
var service = new OasisTest2.ServiceReference1.OasisServiceSoapClient();
System.Net.WebRequest.DefaultWebProxy.Credentials = system.Net.CredentialCache.DefaultNetworkCredentials;
service.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("Username", "Password", "Domain");
var result = service.SelectOfficersAll();
It seems that WebRequest is a global object and you need to set the DefaultWebProxy.Credentails on it.
How you are suppose to know that ? I never found any reference to it when i searched on how to connect to a WCF service on MSDN. Must be a secret. So keep it under your hat.
I'm currently working on a project where we use the Service Bus for Windows Server queues and topics for handling messaging between clients and server. Currently I'm looking into how to handle authentication of the clients and believe we need to use SAS. The clients communicating with the queues can be using both rest and the .net api. I have tried to find resources on best practices especially on how to handle token generation and distribution. For example should we create a service for this that the calling client can connect to providing the access key which would then generate a token returned to the client. Ideas and suggestions would be greatly appreciated.
/Thanks
I would recommend using the WindowsTokenProvider and a Windows user account.
First add a valid Windows user to the Bus with Send permissions on your queue/topic. (You can do this in code or via service bus explorer.)
Then for the Rest API client authentication over Http - You need to post over a valid UserName/Pwd to the STS then add the resulting token to the authorization header of the actual post to the queue.
You can see how to do this here...
For the .Net client over TCP -
Run your client as the same valid windows user, and then call the STS with these implicit credentials by using the TokenProvider.CreateWindowsTokenProvider.
3.1 If you are using the NetMessagingBinding for your client (WCF) then do the following:
var uri = new Uri(string.Format("https://{0}:9355/ServiceBusDefaultNamespace", serverName));
var uris = new List<Uri> {uri};
var securityBehavior = new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateWindowsTokenProvider(uris)
};
var endpoint = new ServiceEndpoint(contract, new NetMessagingBinding(), new EndpointAddress(serviceBusEndpointAddress));
endpoint.Behaviors.Add(securityBehavior);
3.2 NB - The code above will take the implicit credentials of the current principal and pass them across. However, you can explicitly pass in credentials like this:
var securityBehavior = new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateWindowsTokenProvider(uris, new NetworkCredential("myUser", "myPassword"))
};
3.3 Or if you just use the plain .NetClient you can do the same like this:
var uri = new Uri(string.Format("https://{0}:9355/ServiceBusDefaultNamespace", serverName));
var uris = new List<Uri> {defaultUri};
var messagingFactorySettings = new MessagingFactorySettings();
messagingFactorySettings.TokenProvider =
TokenProvider.CreateWindowsTokenProvider(uris, new
NetworkCredential("myUser", "myPassword"));
.....
var factory = MessagingFactory.Create("endpoint", messagingFactorySettings);
I've created a WCF webservice, that can dynamically call other webservices/db connections with DLL's loaded with .LoadFile('from assembly'). Inside one of these assemblies, another webservice is called dynamically with a passed in network credential as follows:
WebClient client = new WebClient();
client.Credentials = this.networkCredential; //This credential is passed in
RequestStream requestStream = client.OpenRead(this.url);
//rest of code. The .OpenRead is giving 401 error (not authorized).
When I do this in debug mode from a test console application and creating the network credentials as follows:
NetworkCredential networkCredential = new NetworkCredential(<userid>,<password>,<domain>);
this works fine.
The failing code is providing networkcredentials as follows
System.Net.NetworkCredential networkCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
Any help would be greatly appreciated.
Unless you are using impersonation, DefaultNetworkCredentials attempts to use the credentials of the process running your ASP.NET website, not the credentials of the user accessing your site. In order to use the credentials of the user, you should wrap your call to the web services in an impersonation context.
var impersonationContext = HttpContext.Current.Request.User.Identity.Impersonate();
if(impersonationContext != null)
{
//call your webservice here. DefaultNetworkCredentials will be what you expect.
impersonationContext.Undo();
}
There are, of course, conditions. The user must be authenticated (can't be an anonymous user, unless the anonymous user also has access to your web service). Also, the code above is just an example - in production code there are quite a few other things to consider. Here is an msdn article that should help get you started.
FYI, the reason it works in development is most likely because your development server process runs as you, and since you have access to the web service, it succeeds.
I have to connecto TFS via API which already works fine when i am within my lan.
But now i have to connect to a TFS over a webproxy. I am able to connect to the serverstatus.asmx via browser.
I already tried to set a environment variable and added the property to app.config - but without success.
Now i tried to do the same with a httpwebrequest
System.Net.HttpWebRequest request = System.Net.WebRequest.Create(tfs_uri) as System.Net.HttpWebRequest;
request.Credentials = tfs_cred;
System.Net.WebProxy p = new System.Net.WebProxy("http://proxy.local.lan:8080/");
p.UseDefaultCredentials = true;
request.Proxy = p;
System.Net.WebResponse response = request.GetResponse();
This code can connect to the tfs. If i remove proxy definition and add the defaultProxy tag into app.config - i get the same error msg when connecting a TfsConfigurationServer object.
My assumption is: TFS API does not support web proxies. Is this correct?
Can somebody tell me that my assumption is wrong?
You can, but it is a bit more convoluted than just setting the proxy details. Because TFS makes lots of seperate calls under the hood you will not be able to use the methods above.
Try adapting Rido's post below:
http://blogs.msdn.com/b/rido/archive/2010/05/06/how-to-connect-to-tfs-through-authenticated-web-proxy.aspx
I would think that you should be able to integrate this method into your own applicaiton.