Here is what is the issue. I'm using portable RestSharp which uses HttpClient under the hood. But for iOS there is problem with HttpClient, because the Default IWebProxy instance doesn't allow to monitor requests using request monitoring software like Charles (look here to see the issue and the solution )
The solution for this is using CFNetwork.GetDefaultProxy () which returns IWebProxy and set it as proxy of a request. I tried setting the Proxy property of RestClient but it didn't work, when digging in the open source code of portable RestClient I found out that the Proxy property is not used anywhere. The only place where it is used is commented out. That method is called ConfigureProxy line 572 in RestSharp.Portable project RestClient file, and this method is called only from ConfigureHttp method line 541 same file, which is also commented out. I believe this is a bug. May be someone has forgotten to set Proxy after commenting out this code. So can someone tell me wether it will be safe to remove the commented line, or may be say the right place where to set the proxy of IHttp interface? For instance is it safe to set the proxy on the line 393 (this is again in the RestClient file) of the attached image, like
httpRequest.Proxy = this.Proxy;
strong text
I fixed this issue by myself after 2 days of debugging RestSharp.Portable 3.1.0 source code.
There is a bug in
RestSharp.Portable.HttpClient.Shared - project
DefaultHttpClientFactory - class
CreateMessageHandler - method
Original code is:
if (handler.SupportsProxy && _proxyProperty != null && proxy != null)
{
_proxyProperty.SetValue(handler, new RequestProxyWrapper(proxy), null);
}
Code does not work because _proxyProperty is null. This field initializes within constructor by reflection.
_proxyProperty = typeof(HttpClientHandler).GetProperty("Proxy");
Simulator initializes this property well, but real iOS device doesn't. I do not know why it happens.
So, here is the code that contains the fix:
if (handler.SupportsProxy && proxy != null)
{
handler.Proxy = new RequestProxyWrapper(proxy);
}
I have added this fix into my application using reflection. If you want to do the same you should wrap your authenticator(s) or implement dummy one and override two methods:
public override bool CanPreAuthenticate(IHttpClient client, IHttpRequestMessage request, ICredentials credentials)
{
return true;
}
and
public override async Task PreAuthenticate(IHttpClient client, IHttpRequestMessage request, ICredentials credentials)
{
...
// get private "handler" field of type DefaultHttpClient from client by reflection here
// get private "proxy" field of type IWebProxy from "handler" by reflection here
// set private "proxy" field if it's null by reflection here
...
}
Hope this help. Do not forget to test your solution on each platform:)
I have added new issue on github FubarDevelopment/restsharp.portable
Related
I have some troubles with the header Expect 100-Continue on a DELETE method inside a .NET 4.5 application. The client in provides also a small content body inside the call.
The official microsoft documentation seems to imply that this header is passed by default only in PUT and POST calls with a non-empty content, but it does not say nothing about DELETE. Does anyone know if this configuration also applies to DELETE?
I'm experiencing different behaviour on different environment of my web application in particular I have some environments in which the header is never passed (even in PUT and POST) without any clue about it being deactivated.
In order to interact with this option I know only four ways:
Via ServicePointManager through
System.Net.ServicePointManager.Expect100Continue = false;
Editing client options
var c = new HttpClient();
c.DefaultRequestHeaders.ExpectContinue = false;
Adding or removing it manually on HttpWebRequest with AddHeader/Remove
Using the following property on Web.Config
<system.net>
<settings>
<servicePointManager expect100Continue="false"/>
</settings>
</system.net>
Unfortunately none of these seems to be my case. Are there any other ways to mess with this option?
Just managed to find out the solution for this issue. I found out that some of my environment use the couchbase client to handle distributed cache, differently from IIS couchbase internally sets Expect100Continue to true but it does that in the following way.
namespace Couchbase.Configuration.Client
{
public class ClientConfiguration {
//...
public ClientConfiguration()
{
//...
this.Expect100Continue = false;
}
//--
public bool Expect100Continue
{
get
{
return ServicePointManager.Expect100Continue;
}
set
{
ServicePointManager.Expect100Continue = value;
}
}
}
}
they use change this property using the static ServicePointManager method and this means that every following instantiated client will change their behaviour.
My version of Couchbase Client is 2.1.4.0
I am trying to create a WebHookHandler for Webhooks send from WordPress WooCommerce in ASP.NET C#.
I started with creating a ASP.NET C# Azure API App WebApplication Project and adding the relevant references (Microsoft.AspNet.WebHooks.Common, Microsoft.AspNet.WebHooks.Receivers, Microsoft.AspNet.WebHooks.Receivers.WordPress). Added the WebHookConfig, WordPressWebHookHandler and registered the WebHookConfig in the GlobalAsax.
I then published the application as an Azure App Service.
My WordPressWebHookHandler is still the default of the examples and looks like this:
public class WordPressWebHookHandler : WebHookHandler
{
public override Task ExecuteAsync(string receiver, WebHookHandlerContext context)
{
// make sure we're only processing the intended type of hook
if("WordPress".Equals(receiver, System.StringComparison.CurrentCultureIgnoreCase))
{
// todo: replace this placeholder functionality with your own code
string action = context.Actions.First();
JObject incoming = context.GetDataOrDefault<JObject>();
}
return Task.FromResult(true);
}
}
When testing a User Creation WebHook in WooCommerce I can see the request in the log as below.
But unfortunately it is never received while debugging and I see below error.
I am thinking maybe I need a custom WebHook instead of the WordPress specific one as this is a WooCommerce Webhook. Or possibly it is handled wrong in the routing and ends up in another controller.
Any help is much appreciated.
Your WebHookReceiver is wrong
There is a mismatch of expecting HTML Form Data, when in fact it should be expecting JSON.
WordPressWebHookHandler is still the default
This is what is causing your error. If you look at the WordPressWebHookReceiver, the ReceiveAsync() method implementation, calls out to ReadAsFormDataAsync() method, which is not what you want, as your Content-Type is json. So, you want to be doing ReadAsJsonAsync().
Solution: Don't use the WordPressWebHookReceiver and switch it to another one that will call ReadAsJsonAsync().
Looking at the code
I am thinking maybe I need a custom WebHook instead of the WordPress specific one as this is a WooCommerce Webhook.
You had the right idea, so I dug up some of the code to explain exactly why this was happening.
The code block below is the ReceiveAsync() method that is overridden in the WordPressWebHookReceiver. You can see that it is calling the ReadAsFormDataAsync() which is not what you want...
public override async Task<HttpResponseMessage> ReceiveAsync(
string id, HttpRequestContext context, HttpRequestMessage request)
{
...
if (request.Method == HttpMethod.Post)
{
// here is what you don't want to be called
// you want ReadAsJsonAsync(), In short, USE A DIFFERENT RECEIVER.
NameValueCollection data = await ReadAsFormDataAsync(request);
...
}
else
{
return CreateBadMethodResponse(request);
}
}
A quick search through the repository for classes that call the ReadAsJsonAsync() method, shows that the following recievers implement it:
DynamicsCrmWebHookReceiver
ZendeskWebHookReceiver
AzureAlertWebHookReceiver
KuduWebHookReceiver
MyGetWebHookReceiver
VstsWebHookReceiver
BitbucketWebHookReceiver
CustomWebHookReceiver
DropboxWebHookReceiver
GitHubWebHookReceiver
PaypalWebHookReceiver
StripeWebHookReceiver
PusherWebHookReceiver
I assumed that the CustomWebHookReceiver would fit your requirements, so can grab the NuGet here. Otherwise you can implement your own, or derive it from this class, etc.
Configuring a WebHook Recevier
(Copied from the Microsoft Documentation)
Microsoft.AspNet.WebHooks.Receivers.Custom provides support for
receiving WebHooks generated by ASP.NET WebHooks
Out of the box you can find support for Dropbox, GitHub, MailChimp,
PayPal, Pusher, Salesforce, Slack, Stripe, Trello, and WordPress but
it is possible to support any number of other providers
Initializing a WebHook Receiver
WebHook Receivers are initialized by registering them, typically in
the WebApiConfig static class, for example:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
// Load receivers
config.InitializeReceiveGitHubWebHooks();
}
}
There is a problem with the data format that you send in your request. You must use format of HTML Form as your error message said.
Proper POST data format is described here: How are parameters sent in an HTTP POST request?
Don't forget to set Content-Length header and correct Content-Type if your library doesn't do it. Usually the content type is application/x-www-form-urlencoded.
I would like to make some additions to Svek's answer as I now got my Proof-of-concept completed and understand a bit more about the receivers.
His answer pointed me in the right direction, but needs a little addition.
WordpressWebHookReceiver
Can take in Wordpress Webhooks of type HttpPost. This does not work with Woocommerce as Woocommerce sends Json Webhook messages and will fail the HttpPost validation which is build into the WordpressWebHookReceiver class.
CustomWebHookReceiver
Can take in custom ASP.NET Webhooks. The custom ASP.NET webhooks have a specific partner for validation which includes but is not limited to the 'ms-signature'. Even adding the header will not suffice as the signature is also used in a different way from out of the box Woocommerce to encrypt the message. Basically coming to a point that you can't integrate Woocommerce with the CustomWebHookReceiver without changing the Webhook classes of Woocommerce.
GenericWebHookReceiver
This is the receiver you want, which accepts basically a generic set of Json data and will be able to use the "code" query parameter to verify the secret which you can add in the web.config of your asp.net api application. I used this receiver to finish the Proof-of-concept and got both the signature validation as well as the deciphering of the message working right of the bat.
My basic class which I will start to build into a real solution can be viewed below and changes the JObject into a dynamic object in the methods I call from the class. As you can see I have two methods currently added, one for the customer create and one for the order create to call the respective methods which do an insert into Dynamics 365 (former CRM).
public class GenericJsonWebHookHandler : WebHookHandler
{
public GenericJsonWebHookHandler()
{
this.Receiver = "genericjson";
}
public override Task ExecuteAsync(string generator, WebHookHandlerContext context)
{
var result = false;
try
{
// Get JSON from WebHook
var data = context.GetDataOrDefault<JObject>();
if(context.Id != "crcu" && context.Id != "cror")
return Task.FromResult(true);
if (context.Id == "crcu")
{
result = WoocommerceCRMIntegrations.Entities.Contact.CreateContactInCRM(data);
}
else if (context.Id == "cror")
{
result = WoocommerceCRMIntegrations.Entities.Order.CreateOrderInCRM(data);
}
}
catch (Exception ex)
{
result = false;
}
return Task.FromResult(result);
}
}
I have a rather outdated assembly that I'm using to communicate via SOAP with software my company writes. As it stands right now, getting the assembly updated is not an option, so please don't suggest it.
In previous iterations the normal method of communication was done utilizing the MS Soap Toolkit 3.0 (MSSOAPLIB30). You would call the login() method of the assembly and it would return an instance derived from IHeaderHandler that you would then assign to the instance of the soap client. Please refer here for more information on how this worked.
Well, I would like to use a more updated approach for communication with this web service. Thus far I have been able to successfully reference the web service with wcf, however I'm running into issues figuring out how to bridge the IHeaderHandler instance to something that the wcf proxy can comprehend. In other words, I'm trying to bridge two generations of technologies together. I've verified that using the method mentioned in the link above does actually work. Now it's just a matter of figuring out how to make this instance of IHeaderHandler useful.
Here is some example code for the old approach:
string strBasicWsdlUrl = "http://" + _strDeviceName + "/MetasysIII/WS/TimeManagement/TimeService.asmx";
object[] Parameters1 = new object[] { strBasicWsdlUrl, "", "", "" };
bool[] Parameters2 = new bool[] { true, true, true, true };
TSClient = Activator.CreateInstance(Type.GetTypeFromProgID("MSSOAP.SoapClient30"));
NewLateBinding.LateGet(TSClient, null, "MSSoapInit", Parameters1, null, null, Parameters2);
Parameters1 = new object[] { NewLateBinding.LateGet(JCISecurity, null, "HeaderHandler", new object[0], null, null, null) };
NewLateBinding.LateSet(TSClient, null, "HeaderHandler", Parameters1, null, null);
As you can see, a new instance of the soap client is initialized with the wsdl file and then the HeaderHandler attribute from the JCISecurity instance (which is the aforementioned assembly I'm using to authenticate with the software) which is derived from IHeaderHandler is passed to the HeaderHandler of the soap client. This process then ensures that all future requests from the soap client have this header attached.
It's also important to note that the proxy class generated from WCF for my web service has two interesting parameters attached to all web methods: EncryptedCertificate and LoginResult. I'm assuming these values will exist in the IHeaderHandler instance as the original documentation of the service does not reference these two parameters. However, I cannot verify this is the case because I've yet to be able to figure out how to access the content embedded in the IHeaderHandler instance.
As it stands, I see two possible solutions at this point: Figure out a way to make the WCF proxy class directly use the IHeaderHandler instance being generated with the assembly or figure out a way to extract the necessary information from the IHeaderHandler instance and use Message Inspectors to manually attach the details to the headers.
WCF is very extensible. One of those extension points is Message Inspectors:
A message inspector is an extensibility object that can be used in the service model's client runtime and dispatch runtime programmatically or through configuration and that can inspect and alter messages after they are received or before they are sent.
See also WCF Extensibility Samples and Extending WCF.
I am using ClientBase in a proxy to call a REST over WCF service of mine using the service interface:
public class CommunicationServiceProxy : ClientBase<ICommunicationService>, ICommunicationService
I also add before each call a authorization header so my service will accept the request, like this:
private OperationContextScope AddHeader(OperationContextScope scope)
{
if (WebOperationContext.Current == null) return null;
WebOperationContext.Current.OutgoingRequest.Headers.Add("Authorization", Header);
return scope;
}
Everything is working fine, but now, because of security resons, I need to generate a signature of the request URL(eg. http://myservice/contact/getstatus?id=1), the problem is how to get this URL when using a proxy class like the one above, seens like WebOperationContext.Current.OutgoingRequest is missing this information.
Anyone have managed to get this? What are my options here?
Thanks
The solution I found is to use WCF extensions, more specificly IClientMessageInspector, there I have all the information I need to generate the signature.
I have created a SoapExtension class to capture the soap request and response from specific web service calls. In order to put this SoapExtension into effect, I have to add an attribute to the method in the generated proxy client.
For example, I've added the AuditSoapCapture attribute to this method:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://blahblah.com/webservices/AddressSearch", RequestNamespace = "http://blahblah.com/webservices/", ResponseNamespace = "http://blahblah.com/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[blahblah.TriadLite.Core.AuditSoapCapture]
public System.Data.DataSet AddressSearch(string HouseNumber, string StreetName, string ZipCode) {
object[] results = this.Invoke("AddressSearch", new object[] {
HouseNumber,
StreetName,
ZipCode});
return ((System.Data.DataSet)(results[0]));
}
I am looking for a way to add this attribute to specific methods without modifying the generated client proxy, as they will get lost when we regenerate. Can I do this in a another partial class or interface or some other way?
Thanks!
Unfortunately, you'll need to modify the proxy code. The other possibilities you mention will not work - a parial class will not overwrite existing functionality, and there is no way that I'm aware of getting an interface to do what you need (compounded by the fact that there is no way to even let the proxy generator know that you intend to implement an interface).
Something that I've done in the past, in a situation where you have access to the source of the webservice, is to write a little app that will parse the code (as text) in the .asmx.cs file of the webservice to extract the names of all the methods that are tagged with [WebMethod]. Then the app "fixes up" the References.cs by inserting appropriate attributes onto the proxied methods, based on some settings file or somesuch. This works well because the naming conventions in the proxy map very neatly to the method names in the original service.
I may just end up injecting my SoapExtension by putting it into the Web.config. This will cause it to be run on every WS call without a client proxy method attribute. Then, I will modify the SoapExtension to look up the called WS method name on a list, and if it is on the list, then do the rest of the SoapExtension logic. I figure the hit on the list in this small volume application isn't going to kill performance.
6 years ago this was posted... So not sure if this will help anyone at this point.
I ran into something similar with a call to an old SOAP web service that had a dynamically generated proxy class that we didn't want to modify as it was auto-generated from the wsdl by the project. In order to solve this problem here is what we did.
The proxy class generated by wsdl.exe is a partial class. We extended this class like so to add a property with the information we wanted to access in the soapextension. You can add as many properties as you want...
partial class mysoapwebservice
{
public string myproperty{ get; set; }
}
in the web.config we registered the soap extension globaly on the project
<webServices>
<soapExtensionTypes>
<add type="MySoapExtension" priority="1" group="Low"/>
</soapExtensionTypes>
</webServices>
In the code were we created the web service object 'mysoapwebservice' we set the value of the property we needed.
In the soapextension you can get a reference to the web service that was called as well as the values. You can also determine the method call.
`
public class MySoapExtension: SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
{
// web service client object
var webserviceobject= ((SoapClientMessage)message).Client;
// method from web service that was called
var calledMethod = (SoapClientMessage)message).MethodInfo;
// checked the client type of webserviceobject and
//added method / property specific logic here
}
}
}
// other soap extension code
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CriptoExtensionAttribute : SoapExtensionAttribute
[CriptoExtension]
public partial class MainService{