How to attach a certificate to a C# client for an ODATA service?
We have an ODATA service which is being secured using certificates. We are using AddWebReference to get the proxy in our C# code.
Is there a way to attach the certificate that is in our certificate store to this generated proxy class?
We can add the certificate using HTTPClient
, but we would like to avoid using HTTPClient
t开发者_开发知识库o talk to our ODATA service and prefer to use the AddWebReference method.
I guess this is probably 3 years too late for you, but hopefully someone else will be helped.
This article actually explains in great detail what is required.
You need to add a ClientCertificate
property to the container generated by adding a web reference and use it. You can do this by creating a partial class that adds the behaviour:
public partial class YourContainer
{
private X509Certificate clientCertificate = null;
public X509Certificate ClientCertificate
{
get
{
return clientCertificate;
}
set
{
if (value == null)
{
// if the event has been hooked up before, we should remove it
if (clientCertificate != null)
this.SendingRequest -= this.OnSendingRequest_AddCertificate;
}
else
{
// hook up the event if its being set to something non-null
if (clientCertificate == null)
this.SendingRequest += this.OnSendingRequest_AddCertificate;
}
clientCertificate = value;
}
}
private void OnSendingRequest_AddCertificate(object sender, SendingRequestEventArgs args)
{
if (null != ClientCertificate)
{
((HttpWebRequest)args.Request).ClientCertificates.Add(ClientCertificate);
}
}
}
On the instantiated container you can now set the ClientCertificate
property with the certificate you need:
// Get the store where your certificate is in.
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
// Select your certificate from the store (any way you like).
X509Certificate2Collection certColl = store.Certificates.Find(X509FindType.FindByThumbprint, yourThumbprint, false);
// Set the certificate property on the container.
container.ClientCertificate = certColl[0];
store.Close();
WCF DataServices 5+ (not completely working)
Now if you're using WCF Dataservice 5+, then the SendingRequest event has been deprecated as indicated with the attribute [Obsolete("SendingRequest2 has been deprecated in favor of SendingRequest2.")]
(not a typo on my side ;) ). I think you can still use it though, however, if you want to use SendingRequest2, your partial should look something like the following:
public partial class YourContainer
{
private X509Certificate clientCertificate = null;
public X509Certificate ClientCertificate
{
get
{
return clientCertificate;
}
set
{
if (value == null)
{
// if the event has been hooked up before, we should remove it
if (clientCertificate != null)
this.SendingRequest2 -= this.OnSendingRequest_AddCertificate;
}
else
{
// hook up the event if its being set to something non-null
if (clientCertificate == null)
this.SendingRequest2 += this.OnSendingRequest_AddCertificate;
}
clientCertificate = value;
}
}
private void OnSendingRequest_AddCertificate(object sender, SendingRequest2EventArgs args)
{
if (null != ClientCertificate)
{
((HttpWebRequestMessage)args.RequestMessage).HttpWebRequest.ClientCertificates.Add(ClientCertificate);
}
}
}
This worked for me for non-batch requests (found by trial and error as I couldn't find a lot of documentation about the differences between the SendingRequest
and SendingRequest2
).
However I seem to be experiencing some trouble now with args.RequestMessage
being of type instead of HttpWebRequestMessage
resulting in InvalidCastExceptions
. Which is actually the reason I ended up on this question. It seems that it only goes wrong with Batch operations. The InternalODataRequestMessage
has a private member requestMessage of type ODataBatchOperationRequestMessage
. It doesn't seem to have any property to which I can add client certificates.
I have posted another question about that specific issue and will change this answer if the implementation I provided here turns out to be the problem.
精彩评论