3/19/2009 1:49:42 PM

Вышел ASP.NET MVC 1.0. Наконец-то.

Качать где всегда - http://www.asp.net/mvc/

11/19/2008 10:40:00 AM

Понадобилось тут такая вот простая функциональность: есть какие-то группы checkbox’ов, списки всякие и т.д, коих (групп) на странице может быть несколько. При этом для каждой группы хочется иметь возможность включить/выключить все checkbox’ы разом. На стороне клиента, конечно, прибегать к коду на сервере тут как-то глупо.

Казалось бы – задача типичная и элементарная, однако поиск в интернете практически ничего не дал, за исключением примитивных циклов по всем контролам формы и циклов по элементам, имена которых задаются по шаблону. А вопросов на эту тему достаточно много.

Это показалось странно: я не хочу задавать шаблоны, я хочу всего лишь указать группу checkbox’ов, которые должны включаться и выключаться одновременно. Поэтому пришлось делать свой контрольчик. С учетом того, что опыта работы с JavaScript я, в общем-то, не имею и с ASP.NET AJAX на уровне скриптов почти не работал, на создание контола у меня ушел примерно час.

Выглядит это теперь примерно так:

<asp:CheckBox 
    runat="server" 
    ID="_checkAllInFirst" 
    Text="First Group (click to check all)" />
<patrolAjax:CheckAllCheckBoxesExtender 
    runat="server" 
    CheckBoxesContainerID="_firstPanel" 
    TargetControlID="_checkAllInFirst" />

<asp:Panel runat="server" ID="_firstPanel">
    <asp:CheckBox ID="CheckBox2" runat="server" Text="First" />
    <asp:CheckBox ID="CheckBox3" runat="server" Text="Second" />
    <asp:CheckBox ID="CheckBox4" runat="server" Text="One more..." />
</asp:Panel>

Моему контролу (CheckAllCheckBoxesExtender) нужно просто “показать” контейнер с checkbox’ами (свойство CheckBoxesContainerID) и “шаблонный” checkbox, который будет включать/выключать остальные checkbox’ы.
Вот так вот все оказалось просто.

Кстати, я делал этот контрол на базе AjaxToolkit, и как-то даже понравилось то, до чего дошла “современная” JavaScript, я уж не говорю об ASP.NET Ajax Framework, который позволяет и наследование, и интерфейсы, и другие “вкусности”. Похоже, что JavaScript сильно изменилась за последние годы, с тех пор, как я ее очень не любил ;)

Исходный код контрольчика прилагается. Я не стал пихать в архив AjaxToolkit, поэтому перед тем, как скомпилировать, нужно будет “починить” референс на эту библиотеку (скачать с http://ajax.asp.net, если ее нет).
Тестово-демонстрационный сайт из одной странички прилагается :)

AjaxControls.zip (23.55 kb)

9/24/2008 12:14:00 PM

Вообще в Composite Web Application Block достаточно неплохо реализована авторизация (она базируется на Security-блоке из Enterprise Library). Но есть и недостаток в этой реализации: правила (rules) можно можно применять к ресурсам в рантайме, но декларировать (задавать) их можно только в конфигурационном файле.

Для тех, кто не сталкивался, объясню: правило (rule) - это некая именованая комбинация ролей и/или пользовательских имен. Например, можно создать правило, разрешающее управлять пользователями, которое будет определяться комбинацией "Роль Администратор или роль Менеджер или пользователь Вася Пупкин".
В конфигурации это задается так:

<rules>
    <add expression="R:Administrator OR R:Manager OR I:pupkin" name="AllowManageUsers"/>
</rules>

А используется это потом вот так, в конфигурационном файле:

<authorization>
   <rule Url="~/BackEnd/ManageUsers.aspx" Rule="AllowManageUsers"/>
</authorization>

Либо вот так, в рантайме:

authorizationRuleService.RegisterAuthorizationRule(url, ruleName);

Понятное дело, что сказав "а", хотелось бы и "б" сказать, то есть, иметь возможность "на лету" определять правила, а не только пользоваться уже имеющимися. Например, это было бы удобно делать при инициализации модуля (в наследнике ModuleInitializer), чтобы каждый модуль имел возможность задать свои собственные правила и применить их к своим ресурсам. Однако, как я уже и сказал, "out of box" такой возможности нет.

Однако, благодаря "сервисной" структуре Composite Web и Enterprise Library, ее можно добавить. Для этого нужно расширить поведение неустраивающих нас сервисов.

В нашем случае это AuthorizationRuleService из Composite Web, который отвечает за авторизацию, но не дает возможности зарегистрировать новое правило, и AuthorizationRuleProvider, который, собственно, и выполняет всю работу и который "заполняется" правилами из конфигурационного файла.

Я просто расширил эти два механизма, написав свою реализацию AuthorizationProvider и IAuthorizationService. Кроме этого сервис авторизации реализует еще и интерфейс IRuleRegisterService, который я ввел для того, чтобы иметь возможность регистрировать правила в рантайме. Код всего этого дела в этом же постинге.

Теперь, когда у  нас есть собственные реализации этих двух вещей, нужно сказать Composite Web, что нужно использовать их вместо дефолтных.

Для регистрации провайдера просто меняем тип в конфигурационном файле:

<securityConfiguration defaultAuthorizationInstance="RuleProvider" defaultSecurityCacheInstance="">
    <authorizationProviders>
        <add type="WebClientApplication.Shell.Providers.ShellAuthorizationRuleProvider, Shell" name="RuleProvider">
            <rules>
                <add expression="R:Administrator OR R:Manager OR I:pupkin" name="AllowManageUsers"/>
            </rules>
        </add>
    </authorizationProviders>
</securityConfiguration>

В случае сервиса идем в ModuleInitializer "главного" модуля (Shell), там есть функция AddGlobalServices, в которой регистрируется сервис IAuthorizationService. Выкидываем эту строчку, а вместо нее пишем:

IAuthorizationService newAuthService
    = globalServices.AddNew<ShellAuthorizationRuleService, IAuthorizationService>();

IRuleRegisterService ruleRegistrator = newAuthService as IRuleRegisterService;
if (ruleRegistrator != null) globalServices.Add<IRuleRegisterService>(ruleRegistrator);

Таким образом мы регистрируем один класс в виде сразу двух сервисов: IAuthorizationService (так, что подмены никто не заметит) и IRuleRegisterService, который позволит нам регистрировать правила "на лету".

Ну а пользоваться всем этим хозяйством - задача уже совсем рутинная:

 

public override void Load(CompositionContainer container)
{
    base.Load(container);

    AddGlobalServices(container.Parent.Services);
    AddModuleServices(container.Services);
    RegisterSiteMapInformation(container.Services.Get<ISiteMapBuilderService>(true));

    IRuleRegisterService ruleRegistrator = container.Services.Get<IRuleRegisterService>();
    if (ruleRegistrator != null) RegisterRules(ruleRegistrator);

    IAuthorizationRulesService rulesService = container.Services.Get<IAuthorizationRulesService>();
    if (rulesService != null) ApplyRules(rulesService);
}

private void ApplyRules(IAuthorizationRulesService rulesService)
{
    rulesService.RegisterAuthorizationRule("~/AdminPage.aspx", "OnlyForAdministrators");
}

private void RegisterRules(IRuleRegisterService ruleRegistrator)
{
    AuthorizationRule commonRule = new AuthorizationRule("OnlyForAdministrators", "R:Administrator");
    ruleRegistrator.RegisterRule("OnlyForAdministrators", commonRule);
}

Выделено то, что добавилось к уже имеющемуся коду инициализатора модуля. Там регистрируются правила (в моем случае всего одно: OnlyForAdministrators), а потом правила регистрируются для авторизации доступа к ресурсам.

WCABAuthorization.zip (4.09 kb)

4/16/2008 12:42:53 AM

Вот здесь можно скачать бесплатный training kit по новшествам ASP.NET 3.5.

Kit содержит материалы и примеры следующих технологий:

  1. ADO.NET Data Services
  2. ADO.NET Entity Framework
  3. ASP.NET MVC
  4. ASP.NET Dynamic Data
  5. ASP.NET AJAX History
  6. ASP.NET Silverlight Controls
4/9/2008 9:02:08 PM
3/21/2008 8:57:07 PM

Вообще, тенденция какая - Майкрософт все больше "открывается" в последнее время.

Вот и сегодня - открыт исходный код ASP.NET MVC, который, впрочем, находится еще в состоянии бета-релиза.

Скачать и посмотреть можно здесь: http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=11833

3/16/2008 5:49:49 PM

Сделал проект с использованием Web Client Software Factory - очень удобная, надо сказать, штука.
"Прикрутил" к этому проекту MS Ajax Toolkit и столкнулся с тем, что веб-сервисы не обрабатываются ObjectBuilder'ом, соответственно, "достучаться" до контроллера модуля не представляется возможным.
Можно, конечно, явно создавать экземпляр контроллера прямо в веб-сервисе, но это тоже ничего не даст в том случае, если контроллер использует какие-то зарегистрированные сервисы, а обычно это так и есть.

Вторично я столкнулся с той же проблемой когда стал делать HttpHandler для множественной загрузки файлов на сервер. Точно так же нужно было работать с имеющейся инфраструктурой (контроллером модуля, сервисами), ведь не писать же повторно тот же самый код, только в обход общей архитектуры?!

Однако, проблема решилась банально просто.
Для HttpHandlers я сделал примитивный базовый класс, от которого наследуются все конкретные обработчики.

public abstract class HttpHandlerBase : IHttpHandler
{
    public HttpHandlerBase()
    {
        WebClientApplication.BuildItemWithCurrentContext(this);
    }
    public abstract bool IsReusable { get; }
    public abstract void ProcessRequest(HttpContext context);
}

То есть, в конструкторе экземпяра мы просто "пропускаем" его через ObjectBuilder (WebClientApplication - это класс приложения Web Client Software Factory) и, соответственно, можем пользоваться всей нужной нам инфраструктурой.

То же самое можно сделать и для веб-сервисов.

3/8/2008 3:18:04 PM

Очень интересная сессия с Mix'08, проведенная Бредом Абрансом (Brad Abrams).
В ней он показывает, как "с нуля" создать достаточно функциональное ASP.NET приложение с использованием новейших "фич" ASP.NET, LINQ, AJAX и т.д.

В своем примере Бред делает фотогалерею.

Рекомендую посмотреть: http://sessions.visitmix.com/?selectedSearch=T34

Tags: ,

12/10/2007 11:13:00 PM

Наконец-то вышел комьюнити превью расширений ASP.NET 3.5

В него входит целый набор интересных и полезных вещей:

ASP.NET MVC

Это та вещь, которую лично я хотел посмотреть больше всего - Model-View-Controller фреймворк для ASP.NET.
Кратко: вся логика работы с моделью располагается в контроллерах, каждый раз, когда пользователь приходит по адресу, скажем, "/Products/Categories/75" запрос автоматически обрабатывается классом контроллера, который может иметь примерно такую структуру:

 

public class ProductsController : Controller
{
    [
ControllerAction]
   
public void Categories(int parentId)
    {
       
//TODO: Do something
       
this.RenderView("Category");
    }
}

При этом весь URL Mapping "ложится на плечи" фреймворка. Естественно, это далеко не все, там и этот самый URL Mapping настраивается, и View с параметрами (а иначе что отображать-то?), и автоматическая загрузка данных из формы view в объект модели, и юнит-тестирование, и многое другое.
Подробнее можно прочитать (с картинками! ;)) "от первого лица":

  • ASP.NET MVC Framework (Part 0): What is it?
  • ASP.NET MVC Framework (Part 1): Building an MVC Application 
  • ASP.NET MVC Framework (Part 2): URL Routing
  • ASP.NET MVC Framework (Part 3): Passing ViewData from Controllers to Views
  • ASP.NET MVC Framework (Part 4): Handling Form Edit and Post Scenarios
  • Поддержка Silverlight и Ajax

    Для того, чтобы сделать на сайте, например, видеоплейер, достаточно добавить контрол:

    <asp:MediaPlayer
           
    MediaSource=http://mysite/mymedia
            MediaSkin="Professional" />

    Естественно, это будет Silverlight, который будет работать на Windows и MacOS в Сафари, Файрфоксе и, разумеется, ИЕ.
    Кроме этого, добавился элемент <asp:Silverlight ...>, позволяющий легко "подключать" silverlight-объекты.

    Что же касается Ajax, то тут существенно улучшена поддержка истории браузера.

    Dynamic Data

    Некоторое время назад я писал о том, что неплохо было бы иметь контрол, отображающий данные переданного объекта (любого) с возможностью валидации. И даже делал такой контрол сам.

    Теперь это возможно с помощью "фичи", которая называется "dynamic data". Здесь мы имеем ряд новых контролов: DynamicDetailsView, DynamicFormView, DynamicGridView и DynamicListView, которые позволят добиться и этого и еще всякого другого.

    Например, если мы напишем:

    <DyanamicGridView id="DynamicGridView" runat="server" 
                                 
    DataSourceID="LinqDataSource1" />

    <asp:LinqDataSource ID="LinqDataSource1" runat="server"
                                   
    ContextTypeName="NorthwindDataContext"
                                   
    TableName="Products" />

    то получим грид, отображающий таблицу Products (представленную в виде модели LINQ to SQL, разумеется) с возможностью изменения\добавления\удаления данных непосредственно в контексте данных (NorthwindDataContext) и валидацией.

    Замечательно так же и то, что в случае, если поля в базе данных связаны по ключу, то вместо безликого числа CategoryId в списке будет отображаться имя этой самой категории, взятое из связанной таблицы!

    Правила же валидации примерно такие же, как и те, что делал я в своем контроле:

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

    Более того, возможности можно расширить с помощью атрибутов Required, Range, Regex и DisplayFormat, "пометив" ими объект модели самостоятельно.

    Подробнее о расширениях ASP.NET 3.5 можно посмотреть и почитать на страницах QuickStart: http://quickstarts.asp.net/3-5-extensions/default.aspx

    Tags:

    11/27/2007 1:30:00 AM

    Некоторое время назад я спрашивал у всех подряд, нет ли на примете простого ASP.NET-контрола, который позволяет редактировать переданный ему объект. Вроде DetailsView, но с валидацией.

    Ни у кого не оказалось. Зато не один человек сказал что-то вроде "найдешь - сообщи". Сообщаю - не нашел. Пришлось писать самому, благо делом оказалось простым, заняло всего пару-тройку часов.

    Что получилось:

    • Обработка объекта, естественно, делается с помощью рефлексии свойств этого объекта.
    • Атрибуты ReadOnly и Browsable учитываются.
    • Атрибуты DisplayName и Description учитываются.
    • Для следующих типов генерируются следующие отображения:
      Enum -> DropDownList; [Flags]Enum -> CheckBoxList; Boolean -> CheckBox; все остальное -> TextBox.
    • Для полей Enum'ов поддерживаются атрибуты Browsable и EnumDisplayName (юзер-френдли имя поля).
    • Для полей, которые будут редактироваться с помощью текстового (и только для них) поля поддерживается валидация.
    • Для валидации свойств используются атрибуты ValidateRequired, ValidateRange и ValidateCompare.
    • Тексты валидаторов задаются в свойствах объекта.
    • Для всех элементов формы редактирования (таблица, лейблы, валидаторы, поля значений) поддерживаются стили, которые можно задать в свойствах или использовать в скинах.

    Иными словами, редактируемый класс может выглядеть так:

    public enum MyEnum
    {
        [EnumDisplayName("Choice one")]
        One = 1,

        [EnumDisplayName("Choice two")]
        Two= 2,

        [EnumDisplayName("NO CHOICE")]
        NoneOfThem =
    4
    }

    public class TestEntry
    {
        [DisplayName("User's name")]
        [Description("The name of the user")]
        [ValidateRequired]
        public string Name { get; set; }

        [DisplayName("User's age")]
        [Description("Age must be more than 20 and less than 45")]
        [ValidateRequired, ValidateRange(20, 45)]
        public int Age { get; set; }

        [DisplayName("User's choice")]
        public MyEnum Choice { get; set; }

        [DisplayName("Man?")]
        public bool IsMan { get; set; }
    }

    Для моих целей этой функциональности хватает с лихвой. Если кому-то будет полезно или интересно - можно что-нибудь подкрутить или добавить, там все очень просто :)

    Код прилагаю.

    [UPDATE]: Там, в коде, используются фичи из только что релизнувшегося .NET Framework 3.5. Как минимум там есть метод, расширяющий EnumConverter, по поводу остального не уверен, не проверял на 2.0. Так что не говорите мне, что оно не компилируется :) Переделать под 2.0, я думаю, 7 минут работы максимум.

    AspNetObjectEditor.zip (5.74 kb)

    Tags:

    Powered by BlogEngine.NET 1.6.0.0

    About the author

    Alexey Raga Alexey Raga
    .NET software developer.

    E-mail me Send mail

    Twitter


    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2010

    Sign in