About .NET, ASP.NET, MVC, C#, WPF, WCF and everything related to .NET and more.

Captcha Mvc [Используем фабрику для управления поведением капчи]

Часто задают вопрос, что делать если необходимо иметь несколько экземпляров капчи с различным поведением?
Для этого вы можете использовать фабрики:

  • CaptchaUtils.CaptchaManagerFactory - используется для создания ICaptchaManager.
  • CaptchaUtils.BuilderProviderFactory - используется для создания ICaptchaBuilderProvider.
  • CaptchaUtils.ImageGeneratorFactory - используется для создания IGenerateImage.
Рассмотрим пример в котором мы будем использовать несколько экземпляров капчи в одном view.
Для этого нам необходимо, чтобы каждый экземпляр имел свои id отличные от других. Сделаем так чтобы для каждого экземпляра капчи был свой объект ICaptchaManager. Напишем этот код в Global.asax.cs:
public const string MultipleParameterKey = "_multiple_";

private static readonly ConcurrentDictionary<int, ICaptchaManager> CaptchaManagers =
    new ConcurrentDictionary<int, ICaptchaManager>();

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    CaptchaUtils.CaptchaManagerFactory = GetCaptchaManager;
}

private static ICaptchaManager GetCaptchaManager(IParameterContainer parameterContainer)
{
    int numberOfCaptcha;
    if (parameterContainer.TryGet(MultipleParameterKey, out numberOfCaptcha))
        return CaptchaManagers
            .GetOrAdd(numberOfCaptcha, CreateCaptchaManagerByNumber);
    //If not found parameter return default manager.
    return CaptchaUtils.CaptchaManager;
}

private static ICaptchaManager CreateCaptchaManagerByNumber(int i)
{
    var captchaManager = new DefaultCaptchaManager(new SessionStorageProvider());
    captchaManager.ImageElementName += i;
    captchaManager.InputElementName += i;
    captchaManager.TokenElementName += i;
    captchaManager.ImageUrlFactory = (helper, pair) =>
                                            {
                                                var dictionary = new RouteValueDictionary();
                                                dictionary.Add(captchaManager.TokenParameterName, pair.Key);
                                                dictionary.Add(MultipleParameterKey, i);
                                                return helper.Action("Generate", "DefaultCaptcha", dictionary);
                                            };
    captchaManager.RefreshUrlFactory = (helper, pair) =>
                                            {
                                                var dictionary = new RouteValueDictionary();
                                                dictionary.Add(MultipleParameterKey, i);
                                                return helper.Action("Refresh", "DefaultCaptcha", dictionary);
                                            };
    return captchaManager;
}
Мы определяем метод GetCaptchaManager для создания экземпляров ICaptchaManager, на входе он принимает интерфейс IParameterContainer, который предоставляет доступ к параметрам. Параметры могут быть взяты из запроса или при создании капчи.
Далее мы объявляем константу MultipleParameterKey, которая хранит ключ для параметра, задающего номер капчи во view.
В методе GetCaptchaManager мы проверяем, если в IParameterContainer есть параметр с именем MultipleParameterKey значит нам необходимо предоставить свой экземпляр ICaptchaManager для обработки. Этим занимается словарь CaptchaManagers и метод CreateCaptchaManagerByNumber.
Метод CreateCaptchaManagerByNumber создает новый экземпляр ICaptchaManager и присваивает уникальное имя для параметров ImageElementName, InputElementName, TokenElementName, а также задает фабрики создания url для изображения и обновления. В них он определяет дополнительный параметр MultipleParameterKey со значением равным текущему номеру.
Далее мы можем определить в одном view несколько экземпляров капчи, пример:
@using CaptchaMvc.HtmlHelpers
@using CaptchaMvc.Models
@using FactoryExample
@{
    ViewBag.Title = "Index";
}

<h2>The default captcha render with Html.Captcha(5, new ParameterModel(MvcApplication.MultipleParameterKey, 0))</h2>
@using (Html.BeginForm())
{
    //Adding a hidden field with a number of captcha
    @Html.Hidden(MvcApplication.MultipleParameterKey, 0)

    //Pass a number of captcha as parameter
    @Html.Captcha(5, new ParameterModel(MvcApplication.MultipleParameterKey, 0))
    <br />
    <input type="submit" value="Send"/>
}


<h2>The captcha render with Html.Captcha("Refresh", "Input", 5, 
new ParameterModel(MvcApplication.MultipleParameterKey, 0))</h2>
@using (Html.BeginForm())
{
    //Adding a hidden field with a number of captcha
    @Html.Hidden(MvcApplication.MultipleParameterKey, 1)

    //Pass a number of captcha as parameter
    @Html.Captcha("Refresh", "Input", 5, new ParameterModel(MvcApplication.MultipleParameterKey, 1))
    <br />
    <input type="submit" value="Send"/>
}

<h2>The captcha render with Html.Captcha("Refresh", "Input", 5, "Is required field.", true, 
new ParameterModel(MvcApplication.MultipleParameterKey, 0))</h2>
@using (Html.BeginForm())
{
    //Adding a hidden field with a number of captcha
    @Html.Hidden(MvcApplication.MultipleParameterKey, 2)

    //Pass a number of captcha as parameter
    @Html.Captcha("Refresh", "Input", 5, "Is required field.", true, new ParameterModel(MvcApplication.MultipleParameterKey, 2))
    <br />
    <input type="submit" value="Send"/>
}
Обратите внимания что при создании капчи мы передаем также дополнительны параметр new ParameterModel(MvcApplication.MultipleParameterKey, номер) и определяем скрытое поле @Html.Hidden(MvcApplication.MultipleParameterKey, номер), это необходимо, чтобы наш метод мог определить какой экземпляр ICaptchaManager использовать. После этих действий мы можем запустить приложение и убедиться, что все работает.
Пример доступен по ссылке.
Таким же образом мы можем определить методы для создания CaptchaUtils.BuilderProviderFactory, CaptchaUtils.ImageGeneratorFactory.

Комментарии
Оставить комментарий
*bold*
_italics_
+underline+
* Bullet List
** Bullet List 2
# Number List
## Number List 2
{"Do not apply formatting"}
{code:language} code here {code:language}.
Supports: aspx c#, c#, c++, html, sql, xml
[url:http://www.example.com]