如何将证书附加到 ODATA 服务的 C# 客户端?

发布于 2024-10-06 14:35:45 字数 222 浏览 3 评论 0原文

我们有一个使用证书保护的 ODATA 服务。我们使用 AddWebReference 在 C# 代码中获取代理。

有没有办法将我们的证书存储中的证书附加到这个生成的代理类?

我们可以使用 HTTPClient 添加证书,但我们希望避免使用 HTTPClient 与我们的 ODATA 服务通信,而更愿意使用 AddWebReference 方法。

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 to talk to our ODATA service and prefer to use the AddWebReference method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凶凌 2024-10-13 14:35:45

我想这对你来说可能已经晚了 3 年,但希望其他人能得到帮助。

这篇文章实际上非常详细地解释了所需的内容。

您需要将 ClientCertificate 属性添加到通过添加 Web 引用生成的容器中并使用它。您可以通过创建一个添加行为的分部类来做到这一点:

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);
        }
    }
}

在实例化的容器上,您现在可以使用所需的证书设置 ClientCertificate 属性:

// 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+(不完全工作)

现在,如果您正在使用 WCF Dataservice 5+,则 SendingRequest 事件已被弃用,如属性 [Obsolete("SendingRequest2 已被弃用,取而代之的是 SendingRequest2。")] (我这边不是拼写错误;))。我认为你仍然可以使用它,但是,如果你想使用 SendingRequest2,你的部分应该看起来像下面这样:

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);
        }
    }
}

这对我来说适用于非批量请求(通过试验和错误发现,因为我找不到很多有关 SendingRequestSendingRequest2 之间差异的文档)。

然而,我现在似乎遇到了一些麻烦,因为 args.RequestMessage 类型而不是 HttpWebRequestMessage 导致 InvalidCastExceptions。这实际上就是我最终提出这个问题的原因。看来只有批量操作才会出错。 InternalODataRequestMessage 有一个 ODataBatchOperationRequestMessage 类型的私有成员 requestMessage。它似乎没有任何可以添加客户端证书的属性。

我已经发布了关于该特定问题的另一个问题,如果我在此处提供的实现证明是问题所在,我将更改此答案。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文