Как подключить кеширование на стороне клиента WCF? - PullRequest
8 голосов
/ 07 апреля 2009

Мое приложение использует корпоративное кэширование на стороне клиента; Я хотел бы избежать написания кода для каждого кешируемого вызова и задаться вопросом, существует ли решение, позволяющее кэшировать вызовы на стороне клиента WCF даже для асинхронных вызовов.

Можно ли это сделать с помощью "поведения" WCF или каким-либо другим способом? Примеры кода?

Ответы [ 4 ]

3 голосов
/ 06 мая 2009

Я сделал это на днях с помощью универсальных методов расширения на клиенте службы WCF (DataServiceClient). Он использует действия и функции для передачи фактических вызовов ServiceClient. Окончательный синтаксис использования клиента немного прикольный (если вам не нравятся лямбды), но этот метод выполняет FaultException / Abort wrapping AND caching:

public static class ProxyWrapper
{
    // start with a void wrapper, no parameters
    public static void Wrap(this DataServiceClient _svc, Action operation)
    {
        bool success = false;

        try
        {
            _svc.Open();
            operation.Invoke();
            _svc.Close();

            success = true;
        }
        finally
        {
            if (!success)
                _svc.Abort();
        }
    }

    // next, a void wrapper with one generic parameter
    public static void Wrap<T>(this DataServiceClient _svc, Action<T> operation, T p1)
    {
        bool success = false;

        try
        {
            _svc.Open();
            operation.Invoke(p1);
            _svc.Close();

            success = true;
        }
        finally
        {
            if (!success)
                _svc.Abort();
        }
    }

    // non-void wrappers also work, but take Func instead of Action
    public static TResult Wrap<T, TResult>(this DataServiceClient _svc, Func<T, TResult> operation, T p1)
    {
        TResult result = default(TResult);

        bool success = false;

        try
        {
            _svc.Open();
            result = operation.Invoke(p1);
            _svc.Close();

            success = true;
        }
        finally
        {
            if (!success)
                _svc.Abort();
        }

        return result;
    }
}

На стороне клиента мы должны называть их так:

    internal static DBUser GetUserData(User u)
    {
        DataServiceClient _svc = new DataServiceClient();

        Func<int, DBUser> fun = (x) => _svc.GetUserById(x);

        return _svc.Wrap<int, DBUser>(fun, u.UserId);
    }

Видишь план здесь? Теперь, когда у нас есть общий набор оболочек для вызовов WCF, мы можем использовать ту же идею для внедрения некоторого кэширования. Здесь я использовал "низкотехнологичные" и просто начал разбрасывать строки для имени ключа кеша ... Вы можете сделать что-то более элегантное с отражением, без сомнения.

    public static TResult Cache<TResult>(this DataServiceClient _svc, string key, Func<TResult> operation)
    {
        TResult result = (TResult)HttpRuntime.Cache.Get(key);

        if (result != null)
            return result;

        bool success = false;

        try
        {
            _svc.Open();
            result = operation.Invoke();
            _svc.Close();

            success = true;
        }
        finally
        {
            if (!success)
                _svc.Abort();
        }

        HttpRuntime.Cache.Insert(key, result);

        return result;
    }

    // uncaching is just as easy
    public static void Uncache<T>(this DataServiceClient _svc, string key, Action<T> operation, T p1)
    {
        bool success = false;

        try
        {
            _svc.Open();
            operation.Invoke(p1);
            _svc.Close();

            success = true;
        }
        finally
        {
            if (!success)
                _svc.Abort();
        }

        HttpRuntime.Cache.Remove(key);
    }

Теперь просто вызовите Cache при чтении и Uncache при создании / обновлении / удалении:

    // note the parameterless lambda? this was the only tricky part.
    public static IEnumerable<DBUser> GetAllDBUsers()
    {
        DataServiceClient _svc = new DataServiceClient();

        Func<DBUser[]> fun = () => _svc.GetAllUsers();

        return _svc.Cache<DBUser[]>("AllUsers", fun);
    }

Мне нравится этот метод, потому что мне не нужно было ничего перекодировать на стороне сервера, только мои прокси-вызовы WCF (которые, по общему признанию, были немного хрупкими / вонючими, чтобы разбросаться повсюду).

Замените в своих собственных соглашениях прокси WCF и стандартных процедурах кэширования, и все готово. Сначала нужно создать много шаблонов-оберток, но я выбрал только два параметра, и это помогает всем моим операциям кэширования использовать одну сигнатуру функции (пока). Дайте мне знать, если это работает для вас или у вас есть какие-либо улучшения.

0 голосов
/ 15 июля 2009

Аналогично приведенному выше решению, проверьте http://www.acorns.com.au/blog/?p=85 (PolicyInjection для служб WCF) Вы можете указать политику, соответствующую имени вашей службы.

0 голосов
/ 08 апреля 2009

Если вы хотите кэшировать без явной реализации его при каждом вызове службы, рассмотрите обработчик кэширования в блоке приложения внедрения политик. Вы можете пометить свои вызовы атрибутом, и блок внедрения политики будет обрабатывать кэширование для вас.

http://msdn.microsoft.com/en-us/library/cc511757.aspx

0 голосов
/ 07 апреля 2009

К сожалению, я думаю, что вам придется кататься самостоятельно. Я не верю, что в WCF встроен механизм кэширования на стороне клиента.

Ответ на этот вопрос также может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...