I am using a WCF client proxy to call a web service. I am adding logging to each request using IClientMessageInspector. I want to get info out of the underlying HTTP message, and found out I can get it by the following:
public class WCFLoggingInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var httpRequest = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
var method = httpRequest.Method;
return null;
}
}
While stepping through in the debugger, this works fine. However, running normally, I get an error from the Properties indexer: "A property with the name 'httpRequest' is not present"
Can anyone explain whats going on here, or an alternate way to get at the HttpRequest? (I'm also doing the same thing for AfterReceiveReply)
It seems that Visual Studio creates this when the debugger is attached.
if (!properties.ContainsKey(HttpRequestMessageProperty.Name))
properties.Add("httpRequest", new HttpRequestMessageProperty());
Source: Property httpRequest' not present
Related
I have a WCF service receiving data from a client. The data in the client has a time stamp in it. As part of some troubleshooting, I used the WCF Trace tools and noticed that the time stamp saved on the client side is serialized with the client time offset in it, but when the message is received on the server, the time offset shows up with the server time offset.
Example:
Client is GMT-2
Server is GMT-7
Trace log on the client has a field in the message that says:
2021-12-02T20:24:10.1234567-02:00
Trace log on the server has that message but the timeStamp listed as:
2021-12-02T20:24:10.1234567-07:00
I found this very strange and tried to dig deeper. My hypothesis was that during deserialization WCF may have automatically converted it, but I would assume that the raw message if printed out as string would have the "-02:00" in it. So I implemented a message filter and output the message using:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
_logger.Information($"message: {request.ToString()}");
...
}
Running this, my logged message however still shows a converted rather than original time stamp.
My next hypothesis was that the Message.ToString method was deserializing it with whatever default deserializer we have. So I tried to use an XMLSerializer to parse just the timestamp out myself:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
var bufferedMessage = request.CreateBufferedCopy(int.MaxValue);
var message = bufferedMessage.CreateMessage();
var xmlOutput = "";
var xmlReader = message.GetReaderAtBodyContents();
while (xmlReader.Read())
{
if (xmlReader.Name == "timeStamp")
{
xmlReader.Read();
_logger.Information($"Raw Timestamp: {xmlReader.Value}");
}
}
_logger.Information($"message :\r\n{xmlOutput}");
request = bufferedMessage.CreateMessage();
return null;
}
Yet I still get the timestamp returned in the server time zone.
This now leaves me out of ideas on what to try next because:
WCF Trace logs on client show that it definitely is putting in the "-2:00" client time zone in there.
MessageInspector logging on the server side shows that it is already converted to "-7:00" server time zone.
The server has no other endpoint behaviors configured (I checked the configuration file as well as the program itself)
The client configuration does not have any other endpoint behaviors configured
I have tried changing the ServiceOperation parameter type to string but get the same result (server timestamp shows up)
Anyone have any ideas on what's going on here or where I should probably check next?
I am using a third party service & hence has no access to change anything from service side. I WSDL which I added as connect service.
The problem is that I have enabled the raw request & I can see error details in trace or debug log. But When I try to fetch details using following code it always return empty Detail Object.
try {
// my code to call service
}
catch (System.ServiceModel.FaultException<Error[]> errors) {
var err = Newtonsoft.Json.JsonConvert.SerializeObject(errors.Detail)
Console.WriteLine(err);
}
Edit: looks to be a duplicate of
FaultException.Detail coming back empty
The problem was the visual studio didn't quite map out the ErrorDetail objects right. The ErrorDetail node is called "ErrorDetail", but the type generated for it is "ErrorDetailType." I edited the reference.cs class generated for each service I was using and added a TypeName:
We recently had to upgrade our Win 8.1 store app to Win 10. Part of that change was modifying our NetTcpBindings to instead be BasicHttpBindings for file uploads since UWP does not currently support NetTcpBindings. Our issue is that when the client calls the UploadFileMethod on the proxy class, we intercept the message before it is sent to the server so we can apply headers that are used later as follows:
public async Task UploadFileAsync(RemoteFileInfo request)
{
using (new OperationContextScope(this.InnerChannel))
{
string nameSpace = #"http://tempuri.org";
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("FileName", nameSpace, request.FileName));
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("Length", nameSpace,
request.Length));
await Channel.UploadFileAsync(request);
}
}
This used to work fine when we were using NetTcpBinding but since we switched to BasicHttpBinding that code is now throwing an exception on the line:
await Channel.UploadFileAsync(request);
With the exception reading:
This message cannot support the operation because it has been written.
After reading up on this exception it appears that we cannot mess with the request object at all before it is sent to the server when using BasicHttpBinding. If that is the case, how can we add OutgoingMessageHeaders to the message using properties of the request itself?
Edit: The proxy class is created as follows:
var imageProxy = new RTMImageServiceProxy(globalContext.Win10UploadBinding,
globalContext.ImageEndpointAddress);
Where Win10UploadBinding is configured as so:
BasicHttpBinding win10BasicBinding = new BasicHttpBinding();
win10BasicBinding.Security.Mode = BasicHttpSecurityMode.None;
win10BasicBinding.TransferMode = TransferMode.Streamed;
win10BasicBinding.SendTimeout = new TimeSpan(0, 0, 2, 0);
win10BasicBinding.MaxReceivedMessageSize = 2147483647;
this.win10UploadBinding = win10BasicBinding;
and globalContext is just a static class I used to store commonly-used variables.
Apparently it turns out that once written cannot be altered so create a copy with adjusted headers. Equivalent issue was brought up here.
Anyway, I encourage you to create custom message inspector: class deriving IClientMessageInspector, as far as client is concerned. It provides separation between method being invoced and headers being adjusted.
I have some trouble when using SPUtility.SendEmail method in a custom workflow.
private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
{
if (SPUtility.IsEmailServerSet(workflowProperties.Site.OpenWeb()))
{
StringDictionary headers = new StringDictionary();
headers.Add("to", "myemailaddress#mailinator.com");
headers.Add("from", "somebody#example.com");
headers.Add("content-type", "text/html");
SPSecurity.RunWithElevatedPrivileges(delegate()
{
bool test = SPUtility.SendEmail(web, headers, "some message body");
});
}
}
in the code's above, the method SPUtility.SendEmail always returning false.
I've even tried to use RunWithElevatedPrivileges, but still the method returns false.
The smtp configuration is not the problem, because the standard email notification when a task is assigned in sharepoint is sent all right.
The strange part is, I have tried this SendEmail method using a timer job, and the method is working perfectly fine.
please somebody help me if there is something i need to add to my method's above.
thanks.
Try to get the web reference in the elevated privileges scope.
I couldn't find the root of this problem.
I decided to do create 2 workflow: the first is to send the email using initiation parameter (build using sharepoint designer). the second one is workflow that initiate the first workflow.
it's now up and running.
Ok, its been a while since I've worked with a Web References. I need a refresher. I think I have about 80% of the code I need to get a response going but I'm missing something. Maybe you can help me :)
Given:
A web method called GetSomething in the list of methods when pointing to a .wsdl url.
This produces a few classes/objects:
GetSomethingRequest
GetSomethingCompletedEventHandler
GetSomethingCompletedEventArgs
myComplexType
Which I use to create this code:
void someMethodToTestResponse()
{
GetSomethingRequest request = new GetSomethingRequest();
// fill in the request
request.myComplexType.Property1 = "Blah";
request.myComplexType.Property2 = "Kachoo";
GetSomethingCompletedEventHandler handler = GetSomethingCompleted_Response;
//.... ok now what?
//handler.Invoke(???)
// at this point I'm supposed to send an object for source (request maybe?)
// and a new instance of GetSomethingCompletedEventArgs but that class is
// asking for stuff that makes me think that is not the right idea.
}
void GetSomethingCompleted_Response(object source, GetSomethingCompletedEventArgs args)
{
// get the result
var result = args.Result;
}
What am I doing wrong? What am I missing? Thanks in advance.
You don't need web service source codes. The web service can be implemented in Java. Creating service reference woks the same, as we really don't know what is on the other side.
So, try Add Service Reference in VS2008 and enter the url to working web service. VS will examine the wsdl on server and generate needed classes for you.
From than on, you just call the service as some ordinary method call. Meaning you don't have to fiddle with requests and http and such details. All that is hidden from you. Except in app.config where many WCF settings can be changed.
Ok, I figured out that I needed to find a Service type class. See this SO Post where it mentions:
private com.nowhere.somewebservice ws;
The issue was that the class they provide wasn't intellisensing for me and I figured it wasn't what I was looking for.
Here is how I would solve my problem:
blah.webservice.SomeMainServiceClass service = new SomeMainServiceClass();
GetSomethingRequest request = new GetSomethingRequest();
// fill in the request
request.myComplexType.Property1 = "Blah";
request.myComplexType.Property2 = "Kachoo";
object myResponse = service.GetSomething(request);