9

Thread.CurrentPrincipalにセットを持つWCFサービスがありServiceConfiguration.ClaimsAuthorizationManagerます。

次のようにサービスを非同期に実装すると:

    public IAsyncResult BeginMethod1(AsyncCallback callback, object state)
    {
        // Audit log call (uses Thread.CurrentPrincipal)

        var task = Task<int>.Factory.StartNew(this.WorkerFunction, state);

        return task.ContinueWith(res => callback(task));
    }

    public string EndMethod1(IAsyncResult ar)
    {
        // Audit log result (uses Thread.CurrentPrincipal)

        return ar.AsyncState as string;
    }

    private int WorkerFunction(object state)
    {
        // perform work
    }

Thread.CurrentPrincipal は、Begin メソッドと WorkerFunction で正しい ClaimsPrincipal に設定されていますが、End メソッドでは GenericPrincipal に設定されています。

サービスの ASP.NET 互換性を有効にしHttpContext.Current.Userて、すべてのメソッドで正しいプリンシパルを使用できることはわかっていますが、これは行いたくありません。

ASP.NET 互換性をオンにせずに Thread.CurrentPrincipal を正しい ClaimsPrincipal に強制する方法はありますか?

4

3 に答える 3

1

私の質問に対する答えではありませんが、.NET 4.5 で同じ問題を示さない WCF サービスを実装する別のアプローチですThread.CurrentPrincipal

    public async Task<string> Method1()
    {
        // Audit log call (uses Thread.CurrentPrincipal)

        try
        {
            return await Task.Factory.StartNew(() => this.WorkerFunction());
        }
        finally 
        {
            // Audit log result (uses Thread.CurrentPrincipal)
        }
    }

    private string WorkerFunction()
    {
        // perform work
        return string.Empty;
    }
于 2014-01-16T22:41:15.317 に答える
0

これに対する有効なアプローチは、拡張機能を作成することです。

public class SLOperationContext : IExtension<OperationContext>
{
    private readonly IDictionary<string, object> items;

    private static ReaderWriterLockSlim _instanceLock = new ReaderWriterLockSlim();

    private SLOperationContext()
    {
        items = new Dictionary<string, object>();
    }

    public IDictionary<string, object> Items
    {
        get { return items; }
    }

    public static SLOperationContext Current
    {
        get
        {
            SLOperationContext context = OperationContext.Current.Extensions.Find<SLOperationContext>();
            if (context == null)
            {
                _instanceLock.EnterWriteLock();
                context = new SLOperationContext();
                OperationContext.Current.Extensions.Add(context);
                _instanceLock.ExitWriteLock();
            }
            return context;
        }
    }

    public void Attach(OperationContext owner) { }
    public void Detach(OperationContext owner) { }
}

現在、この拡張機能は、OperationContext.Current が同じままであるため、スレッドの切り替え間で保持するオブジェクトのコンテナーとして使用されます。

これを BeginMethod1 で使用して、現在のユーザーを保存できます。

SLOperationContext.Current.Items["Principal"] = OperationContext.Current.ClaimsPrincipal;

そして EndMethod1 で、次のように入力してユーザーを取得できます。

ClaimsPrincipal principal = SLOperationContext.Current.Items["Principal"];

編集(別のアプローチ):

public IAsyncResult BeginMethod1(AsyncCallback callback, object state)
{
    var task = Task.Factory.StartNew(this.WorkerFunction, state);

    var ec = ExecutionContext.Capture();

    return task.ContinueWith(res =>
        ExecutionContext.Run(ec, (_) => callback(task), null));
}
于 2014-01-11T09:17:27.317 に答える