How to get http response code from suds client when using faults - wcf

I'm using suds to call a Windows/WCF service like so:
# Setting up my client
client = Client(wsdl, transport = my_transport, location = url, faults = True, headers = my_soap_action_header, cache = None, wsse = my_http_security)
And, I'm getting a response something like this:
(Link){ Id = 12345 Type = "SomeType" }
I know from talking to the developer of the web service that the return value is the ID and type of the object returned, or it will throw an exception.
That said, I'm wondering how to interrogate the suds client for a normal http response code (e.g. 200).

I relise this is an old question but in case anyone else stumbles upon this i'll provide an answer.
you can setup the client with faults = False this then does not throw webFaults when error occur (so you'll have to implement your own error handeling) instead it returns a tuple with
(<status>, <returned-value>)
so for instance (taken from suds documentation)
client = client(url, faults=False)
result = client.service.addPerson(person)
print result
( 200, person ...)
hope that helps(if you ever look back here)

Related

How to get the current TraceId and SpanId

This article, https://devblogs.microsoft.com/aspnet/improvements-in-net-core-3-0-for-troubleshooting-and-monitoring-distributed-apps/, tells me that the field TraceId is available as a correlation id, which is great!
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
=> ConnectionId:0HLR1BR0PL1CH
=> RequestPath:/weatherforecastproxy
RequestId:0HLR1BR0PL1CH:00000001,
SpanId:|363a800a-4cf070ad93fe3bd8.,
TraceId:363a800a-4cf070ad93fe3bd8,
ParentId: Executed endpoint 'FrontEndApp.Controllers.WeatherForecastProxyController.Get
(FrontEndApp)'
In fact, I can see that in our log sink this works as advertised: When web application A serves a request and in doing so invokes web application B, both of them write the same TraceId value to the log.
As far as I understand, any ASP.NET Core application that receives an incoming Request-Id header will attach the same header to outgoing requests, but if the header does not exist on the incoming request, an new value will be generated for the outgoing request.
We have been asked to add that value to the response from web application A, but it is (not surprisingly) not available on the incoming request.
I have been looking at the System.Diagnostics.Activity class, but accessing Activity.Current isn't giving me an instance with anything useful - the TraceID is just {} - i.e. empty.
My question is this: How can I access the TraceId value in the context of a web application?
-S
I had the same problem when I tried to add a header with TraceId value.
Doing some tests with ModelValidation, I saw then in this kind of error response the "traceId" value was correct, but I couldn't obtain this value from http context variable in any way.
Then I went to net core source code to see DefaultProblemDetailsFactory implementation and surprise! The "traceId" value is obtained doing this:
var traceId = Activity.Current?.Id ?? httpContext?.TraceIdentifier;
Yes, you can get THE traceId using Activity static variable.
You can get tracid and spanid in dictionary.
using var subject = _tracer.BuildSpan($"Operation").StartActive();
var spanContext = subject.Span.Context;
var dictionary = new Dictionary<string, string>();
_tracer.Inject(spanContext, BuiltinFormats.TextMap, new TextMapInjectAdapter(dictionary));

.Net Core ReportExecutionServiceSoapClient set credentials

I am using ReportExecutionServiceSoapClient in .Net Core i got the latest version of .net Core and tried to get a report from reporting services to work. after I've used the WCF connection service I was able to add the code with looks like bellow
// Instantiate the Soap client
ReportExecutionServiceSoap rsExec = new ReportExecutionServiceSoapClient(ReportExecutionServiceSoapClient.EndpointConfiguration.ReportExecutionServiceSoap);
// Create a network credential object with the appropriate username and password used
// to access the SSRS web service
string historyID = null;
TrustedUserHeader trustedUserHeader = new TrustedUserHeader();
ExecutionHeader execHeader = new ExecutionHeader();
// Here we call the async LoadReport() method using the "await" keyword, which means any code below this method
// will not execute until the result from the LoadReportAsync task is returned
var taskLoadReport = rsExec.LoadReportAsync(reportPath, historyID);
// By the time the LoadReportAsync task is returned successfully, its "executionInfo" property
// would have already been populated. Now the remaining code in this main thread will resume executing
string deviceInfo = null;
string format = "EXCEL";
// Now, similar to the above task, we will call the RenderAsync() method and await its result
var taskRender = await rsExec.RenderAsync(renderReq);
When it hist renderAsync all falls apart because the credentials for the service are not set anywhere. I've tried to Login async with no success. Also I've tried to set the credentials with SetExecutionCredentialsAsync but I've got and error saying "The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'." I don't know how to change that for ReportExecutionServiceSoapClient.
I have read some posts in which Microsoft guys says that the authentication with a soap is not resolved but for me it seems so close to be true. I feel like I am missing something.
Technology stack: VS 2017, .net Core web api, ssrs 2016, sql server 2016 standard
How can I authenticate the user for this call?
I know this is an old question but I had the same issue and stumbled onto the answer.
After creating the ReportExecutionServiceSoap object you can specify the username and password in the ClientCredentials. I've had success with this using the Basic client credential type. Be sure you are using HTTPS, otherwise your password is sent in plaintext to the reporting server. I also recommend storing the user/password in a secure place and not code.
BasicHttpBinding rsBinding = new BasicHttpBinding();
rsBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
rsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress rsEndpointAddress = new EndpointAddress("https://servername/ReportServer/ReportExecution2005.asmx");
var rsExec = new ReportExecutionServiceSoapClient(rsBinding, rsEndpointAddress);
rsExec.ClientCredentials.UserName.UserName = "username";
rsExec.ClientCredentials.UserName.Password = "pass";

Use Response of a wcf request as request in another receive port

Is there any way to use the response of a wcf service method request as an input for the next request in same orchestration and return the response of the first request as well as the response of the second request as out put in BizTalk?
Eg :
My first request gives a response as "a"
Give this response "a" as request to the 2nd request and gets the response as "b"
Return the response as "a" and "b".
Is this possible?
Yes. You could either create a map from Response 1 to Request 2, and also create a multiple input message map from Response 1 and Response 2 to your final output message.
If the messages involved don't have any repeating structures, it may be enough to distinguish the fields that you need to be concerned with and just use a ConstructMessage with an XmlDocument, i.e.
// construct shape code
varXmlDoc = new System.Xml.XmlDocument();
varXmlDoc.LoadXml("<webSvcRequest2 xmlns=''><ParamB>" + msgWebSvcResp1.ParamA + "</ParamB></webSvcRequest2>");
msgWebSvcReq2 = varXmlDoc;
And similar code for producing the final output message. If you go this route, I'd advice creating some C# utility methods to actually store the strings/message templates.

Porting Cryptsy authenticatedAPI to Python 3

I am trying to port a class I use to connect to Cryptsy's authenticated API to Python 3.3. I have managed to solve the data type issues, and am getting something that is at least getting a request from the website, but it is rejecting my authentication, this is the code, API keys are not included, for obvious reasons...:
req['method'] = method
req['nonce'] = int(time.time())
post_data = urllib.parse.urlencode(req)
sign = hmac.new(self.Secret, str.encode(post_data), hashlib.sha512).hexdigest()
headers = {
'Sign': sign,
'Key': self.APIKey
}
print('headers: ',headers)
print('post data: ',post_data)
b=urllib.parse.urlencode(headers)
print(b)
test=post_data + '&'+ b
print('test: ',test)
data=test.encode()
print('data: ',data)
ret = urllib.request.urlopen(urllib.request.Request('https://www.cryptsy.com/api', data))
q=ret.read()
w=q.decode()
e=json.loads(w)
return self.post_process(e)
And this is the response from the server:
{'error': 'Unable to Authorize Request - Check Your Post Data', 'success': '0'}
Thanks.
The original script had the DATA and HEADERS components for the Request, but was somehow formatted in a way that confused Python 3 into thinking the HEADERS part was a TIMEOUT argument, and throwing an error about it needing to be an INT. This sent me on a wild goose chase of trying to concatenate the DATA and HEADERS.

Accessing the HTTP headers from a WCF Service

I need to access the HTTP response headers that are to be returned to the client from a WCF Service. Accessing the HTTPContext is easy(through HttpContext.Current.Response), but what is the event/extension/behavior that is executed lastly, when the StatusCode is already set (for ex. if the status is 500)?
EDIT: Message Inspectors don't seem to be a good solution here, because at the time they run, the status code isn't set yet. (At least in my trial that was the case)
You can access all headers on WebOperationContext.Current.IncomingRequest, like this:
IncomingWebRequestContext request = WebOperationContext.Current.IncomingRequest;
WebHeaderCollection headers = request.Headers;
Console.WriteLine("-------------------------------------------------------");
foreach (string headerName in headers.AllKeys)
{
Console.WriteLine(headerName + ": " + headers[headerName]);
}
Console.WriteLine("-------------------------------------------------------");
See here
Simplest way for having control on the Headers is to use Message contracts.
Use Message Inspectors to monitor the message right after receiving it at the Service end.
In an extreme case, where you are not satisfied with any other standard routes, you can go for POX (Plain Old XML) type operations where you would be dealing with raw XML message.