Статьи

Upshot.js & Knockout.js: клиент HTML5 для служб RIA WCF

Поскольку Microsoft оставляет трек Silverlight и все больше и больше сосредотачивается на HTML5 для кросс-браузерной поддержки, появляются решения для нескольких существующих платформ. Одна из вещей, на которую я смотрел, — это возможность повторно использовать существующие службы RIA, которые вы в настоящее время используете для своего приложения Silverlight, и перенести их на веб-сайт с поддержкой HTML5.

HTML — клиент для RIA Services начал как JQuery плагин называется Ria.js . В настоящее время этот проект размещен в одностраничном приложении ASP.NET . Это новый шаблон проекта для создания одностраничных приложений. Преимущество таких приложений заключается в том, что они полностью запускаются в браузере, поэтому довольно просто включить ваше приложение в автономном режиме.

Платформа JS-клиента, используемая для связи с сервером, — Upshot.js. Эта структура предоставляет богатый контекст для объекта, используемого на стороне клиента, включая отслеживание изменений, разбиение на страницы, сортировку и т. Д. Более подробную информацию по этой теме можно найти в блоге Denver Developers . Если вы предпочитаете смотреть живую демонстрацию , Стив Сандерсон дал ее на TechDays Netherlands.

При поиске в сети дополнительной информации я заметил, что большинство примеров посвящено использованию веб-API для связи с сервером. Рядом со стандартным поставщиком Web API для upshot есть также поддержка RIA и OData. Поскольку мой пост посвящен службам RIA, я буду обрабатывать riaDataProvider.

Создание живого демо

приработок:

Итак, давайте начнем с создания нового проекта MVC4:

Создать проект SPAWithRiaServices

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

Создайте проект SPAWithRiaServices, шаг 2

Этот шаблон уже включает некоторые модели, элементы управления и представления, но когда мы откроем папку скриптов, мы увидим ссылки на скрипты для upshot.js, knockout.js,… всего, что нам нужно для создания приложения HTML5 с богатым контекстом. Но эти фреймворки развиваются быстро, и, слава богу, у нас есть вещь под названием Nuget, поэтому мы можем легко обновить ее до последней версии. Так что это будет следующий шаг в моем руководстве, обновление до последней версии одностраничного приложения. Найдите SinglePageAppliction в проводнике управления пакетами Nuget или введите следующее в проводнике диспетчера пакетов:

    Install-Package SinglePageApplication.CSharp

Как только это будет сделано, нам нужно добавить ссылку на ServiceModel, чтобы мы могли использовать класс domainService служб RIA. Следующие ссылки необходимо добавить (обратите внимание, что эти ссылки взяты из последней версии WCF Ria Services SDK V1, C: \ Program Files (x86) \ Microsoft SDKs \ RIA Services \ v1.0 \ Libraries \ Server):

System.ServiceModel.DomainServices.Hosting
System.ServiceModel.DomainServices.Server

И одна ссылка из SP2 пакета WCF Ria Services SDK V1, C: \ Program Files (x86) \ Microsoft SDKs \ RIA Services \ v1.0 \ Toolkit \ Libraries \ Server \ SP2 \

Microsoft.ServiceModel.DomainServices.Hosting

После добавления ссылок нам нужно настроить наши DomainServices. Первое, что нам нужно сделать, это добавить новый раздел конфигурации для DomainService

<configSections>
  <sectionGroup name="system.serviceModel">
    <section name="domainServices" type="System.ServiceModel.DomainServices.Hosting.DomainServicesSection, 
      System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, 
      Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
      allowDefinition="MachineToApplication" requirePermission="false" />
  </sectionGroup>
</configSections>

Затем мы добавляем новый httpModule для DomainService в раздел system.web

<system.web>
  <httpModules>
    <add name="DomainServiceModule" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, 
      System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, 
      Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </httpModules>
</system.web>

В разделе system.webServer мы добавляем новый модуль для DomainService.

<system.webServer>
  <validation validateIntegratedModeConfiguration="false" />
  <modules runAllManagedModulesForAllRequests="true">
    <add name="DomainServiceModule" preCondition="managedHandler" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, 
       System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, 
       Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </modules>
</system.webServer> 

В качестве последнего добавим следующий раздел конфигурации system.serviceModel. Здесь самое важное, что мы добавляем конечную точку JSON, и на этой конечной точке мы добавляем атрибут transMetadata = ”true”, чтобы метаданные отправлялись нашему клиенту HTML.

<system.serviceModel>
  <domainServices>
    <endpoints>
      <add name="JSON" type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, 
       Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, 
       Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
       transmitMetadata="true" />
    </endpoints>
  </domainServices>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
        multipleSiteBindingsEnabled="true" />
</system.serviceModel>

Как только все ссылки и разделы конфигурации будут добавлены, мы можем начать кодировать. Первое, что мы делаем, это добавляем новый класс и позволяем ему наследовать от DomainService.

using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using SPAWithRiaServices.Models;
 
namespace SPAWithRiaServices.Services
{
    /// <summary>
    /// Domain Service responsible for todo items.
    /// </summary>
    [EnableClientAccess]
    public class TodoItemDomainService : DomainService
    {
        [Query(IsDefault = true)]
        public IQueryable<TodoItem> GetTodoItems()
        {
            IList<TodoItem> todoItems = new List<TodoItem>();
 
            todoItems.Add(new TodoItem() 
                { TodoItemId = 1, Title = "Todo item 1", IsDone = false });
            todoItems.Add(new TodoItem() 
                { TodoItemId = 2, Title = "Todo item 2", IsDone = false });
            todoItems.Add(new TodoItem() 
                { TodoItemId = 3, Title = "Todo item 3", IsDone = false });
            todoItems.Add(new TodoItem() 
                { TodoItemId = 4, Title = "Todo item 4", IsDone = false });
 
            return todoItems.AsQueryable<TodoItem>();
        }
    }
}

Класс TodoItem выглядит следующим образом:

using System.ComponentModel.DataAnnotations;

namespace SPAWithRiaServices.Models
{
    public class TodoItem
    {
        [Key]
        public int TodoItemId { get; set; }
        [Required]
        public string Title { get; set; }
        public bool IsDone { get; set; }
    }
}

Теперь мы можем перейти к редактированию представлений. Первое представление, которое нам нужно изменить, — это _Layout.cshtml в общей папке. Здесь мы удаляем следующую строку:

<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script>

И вместо этого добавьте следующие ссылки:

<script src="~/Scripts/jquery-1.6.2.js" 
        type="text/javascript"></script>
<script src="~/Scripts/modernizr-2.0.6-development-only.js" 
        type="text/javascript"></script>
<script src="~/Scripts/knockout-2.0.0.debug.js" 
        type="text/javascript"></script>
<script src="~/Scripts/upshot.js" 
        type="text/javascript"></script>
<script src="~/Scripts/upshot.compat.knockout.js" 
        type="text/javascript"></script>
<script src="~/Scripts/upshot.knockout.extensions.js" 
        type="text/javascript"></script>
<script src="~/Scripts/native.history.js" 
        type="text/javascript"></script>
<script src="~/Scripts/nav.js" 
        type="text/javascript"></script>

В index.cshtml в домашней папке мы добавляем следующее:

Конфигурация для использования upshot

<script type='text/javascript'>
    upshot.dataSources = upshot.dataSources || {};
    
    upshot.dataSources.GetTodoItems = upshot.RemoteDataSource({
        providerParameters: { 
            url: "/SPAWithRiaServices-Services-TodoItemDomainService.svc", 
            operationName: "GetTodoItems" 
        },
        provider: upshot.riaDataProvider,
        bufferChanges: true,
        dataContext: undefined,
        mapping: {}
    });
</script>

Нокаут вид

<ol data-bind="foreach: todoItems">
    <li><strong data-bind="text: Title"></strong>
        <label>
            <input data-bind="checked: IsDone" type="checkbox" />
            Done
        </label>
    </li>
</ol>

И как последнее определение ViewModel

<script type="text/javascript">
    function TodoItemViewModel() {
        // Data
        var self = this;
        self.dataSource = upshot.dataSources.GetTodoItems.refresh();
        self.localDataSource = upshot.LocalDataSource({ 
                                    source: self.dataSource
                                  , autoRefresh: true });
        self.todoItems = self.localDataSource.getEntities();
    }
 
    $(function () {
        ko.applyBindings(new TodoItemViewModel());
    });
</script>

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

Вывод

В ваших HTML-приложениях вы можете использовать свои существующие сервисы RIA с минимальными усилиями. На данный момент возможности ограничены, но я думаю, что в будущем мы сможем использовать все функции, которые присутствуют в SL. При добавлении атрибута TransferMetadata в нашу конечную точку JSON нет необходимости снова определять модель на стороне клиента.