Эта статья была спонсирована Microsoft . Спасибо за поддержку спонсоров, которые делают возможным использование SitePoint.
Добро пожаловать в нашу серию статей с использованием современной IDE от Microsoft: Visual Studio Community 2015 для быстрого проектирования и создания привлекательного, функционального сайта для клиента. Если вы пропустили предыдущие взносы, ознакомьтесь с ними ниже:
- Visual Studio Community 2015: настройка сайта
- Visual Studio Community 2015: добавление электронной почты и контактных страниц
В этой статье мы собираемся добавить решение для электронной коммерции на наш сайт. Решение будет простым, состоящим из одной страницы для обработки корзины покупок, информации об оплате и сообщениях об успехах или неудачах для пользователя.
Мы отправим нашу платежную информацию в фиктивное приложение ASP.NET Web API. Приложение Web API будет действовать как процессор кредитных карт. Он будет использовать JSON через POST. Затем он вернет код состояния HTTP, указывающий на успех или неудачу. На основании этой обратной связи мы можем определить, что делать. Но мы сделаем это просто, показав пользователю сообщение на основе полученного кода состояния.
Хотя решение простое, оно продемонстрирует основные компоненты любого решения для электронной коммерции. Это включает:
- Распечатка продуктов для покупки
- Возможность добавлять или удалять продукты
- Общая стоимость продуктов и покупки
- Форма для сбора платежной информации
- Подключение к стороннему процессору кредитной карты
- Возможность отображения результата от процессора кредитной карты
- В случае успеха доставьте купленный товар
Страница оформления заказа будет оформлена в Bootstrap и использует немного AngularJS, чтобы помочь с небольшим динамическим отображением итогов продукта. Окончательный результат будет выглядеть следующим образом:
Создание страницы оформления заказа
Чтобы создать страницу оформления заказа, нам нужно добавить представление и несколько классов моделей.
Откройте папку Views, затем Home. Щелкните правой кнопкой мыши домашнюю папку и выберите, чтобы добавить новый элемент. Выберите MVC View Page. Назовите файл Checkout.cshtml.
Мы собираемся еще раз стилизовать нашу страницу, используя Bootstrap, ссылку на которую мы уже добавили. Следующий код создаст нашу страницу оформления заказа:
<form action="Checkout" method="post"> <p> <div class="container" ng-controller="ctrl"> <div class="row"> <div class="col-sm-12"> <div class="panel panel-info"> <div class="panel-heading"> <div class="panel-title"> <div class="row"> <div class="col-sm-12"> <h5><span class="glyphicon glyphicon-shopping-cart"></span> Shopping Cart</h5> </div> </div> </div> </div> <div class="panel-body"> <div class="row"> <div class="col-sm-6"> <h4 class="product-name"><strong>Lesson 1</strong></h4> <h4><small>Beginner Lessons</small></h4> </div> <div class="col-sm-4"> <div class="col-sm-6 text-right"> <h6><strong>97.00 <span class="text-muted">x</span></strong></h6> </div> </div> <div class="col-sm-2"> <input type="text" ng-model="lesson1_1000" name="lesson1_1000" placeholder="0" class="form-control input-sm"> </div> </div> <hr> <div class="row"> <div class="col-sm-6"> <h4 class="product-name"><strong>Lesson 2</strong></h4> <h4><small>Intermediate Lessons</small></h4> </div> <div class="col-sm-4"> <div class="col-sm-6 text-right"> <h6><strong>97.00 <span class="text-muted">x</span></strong></h6> </div> </div> <div class="col-sm-2"> <input type="text" ng-model="lesson2_1010" name="lesson2_1010" placeholder="0" class="form-control input-sm"> </div> </div> <hr /> <div class="row"> <div class="col-sm-12"> <div class="form-group col-sm-6"> <label for="cardName">NAME</label> <div class="input-group"> <input type="text" class="form-control" name="cardName" placeholder="Name On Card" /> </div> </div> </div> </div> <div class="row"> <div class="col-sm-12"> <div class="form-group col-sm-6"> <label for="cardNumber">CARD NUMBER</label> <div class="input-group"> <input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" /> </div> </div> </div> </div> <div class="row"> <div class="form-group col-sm-8"> <div class="col-sm-4"> <label>EXPIRATION</label> </div> <div class="col-sm-3"> <label for="cardCv">CV CODE</label> </div> </div> </div> <div class="row"> <div class="form-group col-sm-6"> <div class="col-sm-3"> <input type="text" class="form-control" name="cardYear" placeholder="YY" /> </div> <div class="col-sm-3"> <input type="text" class="form-control" name="cardMonth" placeholder="MM" /> </div> <div class="col-sm-3"> <input type="text" class="form-control" name="cardCv" placeholder="CV" /> </div> <div class="col-sm-3"></div> </div> </div> <hr> </div> <div class="panel-footer"> <div class="row text-center"> <div class="col-sm-9"> <h4 class="text-right">Total $<strong>{{lesson1_1000 * 97 + lesson2_1010 * 97}}</strong></h4> </div> <div class="col-sm-3"> <button type="submit" class="btn btn-success btn-block"> Purchase </button> </div> </div> </div> </div> </div> </div> </div>
К этому коду уже добавлен AngularJS. Прежде чем мы обсудим код AngularJS, давайте немного поговорим о макете формы и ее функциональности.
Для простоты весь наш заказ оформляется в одной форме. Это достигается путем отображения доступных уроков на той же странице. Пользователь может увеличить количество уроков. Это также будет суммировать цену рядом с кнопкой «Оформить заказ». Если пользователь хочет удалить элемент, он просто устанавливает количество обратно на ноль.
AngularJS Функциональность
AngularJS используется для обновления итоговой цены и отображения сообщения об ошибке или успехе. Чтобы добавить AngularJS в проект, откройте файл bower.json
и добавьте ссылку на AngularJS, как показано в последней строке ниже:
"jquery-validation": "1.11.1", "jquery-validation-unobtrusive": "3.2.2", "hammer.js": "2.0.4", "bootstrap-touch-carousel": "0.8.0", "angularjs": "*"
С AngularJS мы можем суммировать цены, потому что количество продукта определяется динамически, как показано ниже
<input type="text" ng-model="lesson1_1000" name="lesson1_1000" placeholder="0" class="form-control input-sm">
ng-model
привязывает значение входного текстового поля к lesson1_1000. Затем мы рассчитываем сумму, используя:
<h4 class="text-right">Total $<strong>{{lesson1_1000 * 97 + lesson2_1010 * 97}}</strong></h4>
Мы берем количество товара и умножаем его на цену товара. Чтобы гарантировать, что мы не получим что-то вроде «NaN» вместо общей цены, нам нужно инициализировать наши переменные AngularJS. Вот где приходит файл controller.js.
Чтобы добавить файл контроллера, откройте папку wwwroot и добавьте папку «js». Затем щелкните правой кнопкой мыши и добавьте controller.js
:
Мы определяем наш контроллер AngularJS в этом файле следующим образом:
angular.module('myapp', []).controller('ctrl', ['$scope', function ($scope) { function init() { $scope.lesson1_1000 = 0; $scope.lesson2_1010 = 0; } init(); }] );
Все, что мы делаем, это инициализируем переменные продукта до нуля. Затем мы вызываем функцию init()
для выполнения кода.
Нам нужно добавить ссылки «myapp» и «ctrl» на стороне клиента. Откройте _Layout.cshtml и измените тег body следующим образом:
<body ng-app="myapp">
Теперь откройте Checkout.cshtml и измените div «container» следующим образом:
<div class="container" ng-controller="ctrl">
Это гарантирует, что наши переменные продукта находятся в правильной области. Пока мы здесь, перетащите файл controller.js
в раздел _Layout.cshtml
. Это создаст ссылку на файл контроллера, как показано ниже:
<script src="~/js/controller.js"></script>
Вы, вероятно, заметили следующий код внизу нашего Checkout.cshtml
:
<div ng-hide="@Model.DisplaySuccess" class="alert alert-success" role="alert">Thank you for your purchase.<br /> You can <a href="/downloads/@Model.DownloadCode">download your product here</a>.</div> <div ng-hide="@Model.DisplayError" class="alert alert-danger" role="alert">Sorry. Your card was declined. Please contact your bank or use another card.</div>
ng-hide
будет скрывать связанный div, когда выражение в нем истинно. В этом случае мы отправляем только значение true или false. Это значение доступно через синтаксис Razor. Модель, которую мы отправляем обратно с представлением, содержит два вышеуказанных свойства. Их значения устанавливаются в зависимости от ответа нашей транзакции обработки.
Модельные классы
Прежде чем мы начнем модифицировать контроллер, мы добавим несколько необходимых классов моделей. Добавьте следующие файлы (классы) в папку Models: Form.cs
, Form.cs
и Checkout.cs
.
В Checkout.cs
добавьте следующее:
public class Checkout { public string DisplayError { get; set; } public string DisplaySuccess { get; set; } public string DownloadCode { get; set; } }
Этот код используется только для того, чтобы скрыть или показать наши сообщения об ошибках и ошибках. DownloadCode создает код, который можно добавить к URL-адресу, имитируя страницу загрузки для приобретенных уроков. Мы отправляем экземпляр класса Checkout обратно с представлением.
Добавьте следующее в Product.cs
:
public class Product { public int Id { get; set; } public string Name { get; set; } public int Price { get; set; } } class FormProduct { public int Id { get; set; } public int qty { get; set; } } class ProductManager { public static int productTotal(List<FormProduct> formProducts) { int total = 0; List<Product> products = ProductManager.GetProducts(); foreach (var item in formProducts) { var match = products.Where(x => x.Id == item.Id).FirstOrDefault(); if (match != null) { total += (match.Price * item.qty); } } return total; } public static List<Product> GetProducts() { List<Product> products = new List<Product>(); Product lesson1 = new Product() { Id = 1000, Name = "Lesson 1", Price = 97 }; Product lesson2 = new Product() { Id = 1010, Name = "Lesson 2", Price = 97 }; products.Add(lesson1); products.Add(lesson2); return products; }
Приведенный выше код содержит все наши классы, связанные с продуктом. Продукт — это наш основной класс продуктов, содержащий экземпляры продуктов. FormProduct — это проводной класс. Он предназначен для перевода необработанных данных формы в класс Product. ProductManager является вспомогательным классом. Он суммирует цены на продукты, поступающие из формы. GetProducts () — это смоделированный метод, который напоминает получение продуктов из источника данных.
Наконец, добавьте следующий класс в Form.cs:
public class myForm { public string lesson1_1000 { get; set; } public string lesson2_1010 { get; set; } [JsonProperty("cardName")] public string cardName { get; set; } [JsonProperty("cardNumber")] public string cardNumber { get; set; } [JsonProperty("cardYear")] public string cardYear { get; set; } [JsonProperty("CardMonth")] public string CardMonth { get; set; } [JsonProperty("CardCv")] public string CardCv { get; set; } [JsonProperty("totalPrice")] public int totalPrice { get; set; } }
Этот класс будет служить двойной цели. Он будет привязан к нашим полям формы, упрощая доступ к ним в контроллере. Поскольку этот экземпляр будет содержать всю информацию о платеже, было бы неплохо просто использовать ее, когда мы отправляем процессору электронной торговли?
Благодаря добавлению totalPrice у нас есть все необходимое для обработки платежа, что позволяет нам сериализовать myForm и отправлять его обработчику платежей.
Сбор отправленных данных формы
Основная обработка для нашей страницы оформления заказа происходит в файле HomeController.cs. Создайте следующий метод:
[HttpPost] public IActionResult Checkout(myForm form) { Checkout c = new Checkout(); List<FormProduct> products = new List<FormProduct>(); if (!string.IsNullOrEmpty(form.lesson1_1000)) { products.Add(new FormProduct() { Id = 1000, qty = Convert.ToInt16(form.lesson1_1000) }); } if (!string.IsNullOrEmpty(form.lesson2_1010)) { products.Add(new FormProduct() { Id = 1010, qty = Convert.ToInt16(form.lesson2_1010) }); } form.totalPrice = ProductManager.productTotal(products); var url = "http://localhost:50672/api/values/"; string serializedData = JsonConvert.SerializeObject(form, Formatting.None); serializedData = JsonConvert.SerializeObject(serializedData); using (var client = new WebClient()) { client.Headers[HttpRequestHeader.ContentType] = "application/json"; var result = client.UploadData(url, "POST", Encoding.ASCII.GetBytes(serializedData)); var response = System.Text.Encoding.UTF8.GetString(result); var decode = JsonConvert.DeserializeObject(response); c.DisplaySuccess = "true"; c.DisplayError = "true"; if (response.Contains("200")) { c.DisplaySuccess = "false"; c.DownloadCode = DateTime.Now.Ticks.ToString(); } else if (response.Contains("406")) { c.DisplayError = "false"; } } return View(c); }
Мы начнем с создания экземпляра класса Checkout
. Это не будет использоваться до конца метода, когда мы получим ответ от поддельного стороннего процессора электронной коммерции.
Затем мы преобразуем наши поля формы в экземпляры FormProduct. Параметр Checkout () имеет тип myForm. Эти классы позволяют связывать поля формы, облегчая доступ к ним. Класс myForm находится ниже и определяется в верхней части HomeController:
Мы называем:
form.totalPrice = ProductManager.productTotal(products);
… Чтобы получить полную стоимость представленных продуктов. Мы присваиваем итог обратно экземпляру myForm
. Как упоминалось ранее, мы можем отправить этот класс в процесс электронной коммерции, сериализовав его, что мы и сделаем дальше.
Вы можете видеть, что serliaization происходит дважды. Это может быть больше проблема с JsonConvert. Не выполняя сериализацию дважды, наш JSON искажен и приведет к нулевой отправке процессору электронной коммерции.
Прежде чем двигаться дальше, давайте добавим пакет Nuget для класса сериализации JSON — JsonConvert.
Щелкните правой кнопкой мыши узел «Ссылки» в обозревателе решений. Нажмите Управление пакетами Nuget. Поиск Newtonsoft.Json
. На скриншоте ниже видно, что я его уже добавил:
Затем мы ставим в очередь вызов нашего приложения Web API. Приложение Web API должно быть запущено, так как мы ссылаемся на его локальный URL.
client.Headers[HttpRequestHeader.ContentType] = "application/json"; var result = client.UploadData(url, "POST", Encoding.ASCII.GetBytes(serializedData)); var response = System.Text.Encoding.UTF8.GetString(result); var decode = JsonConvert.DeserializeObject(response);
Как только ответ возвращается, мы десериализуем его и ищем конкретные ответы. Если бы это был реальный ответ электронной коммерции, мы бы не просто искали строку. Вероятно, будет немного больше структуры для получения ответа.
Мы устанавливаем значения для отображения и сокрытия успешных или неудачных дивов.
Успех будет выглядеть следующим образом:
Вы можете увидеть нашу ссылку для загрузки продукта.
Отказ будет выглядеть так:
Вы можете просто изменить тип возвращаемого значения в приложении Web API, чтобы имитировать разные ответы.
Обработка электронной коммерции
Обработка электронной торговли будет в основном подвергаться насмешкам с помощью приложения Web API. Мы разместим POST в одной конечной точке в приложении Web API. С этой же конечной точки мы получим успех или неудачу в транзакции.
В то время как сторонние решения для электронной коммерции сильно различаются, мы будем использовать минимальное, но стандартное решение. Мы отправим информацию о платеже пользователя вместе с общей суммой, которую необходимо оплатить.
Чтобы создать приложение веб-API, выберите «Файл»> «Новый проект»> «Веб-приложение ASP.NET»> «Веб-API»:
Изменения, которые нам нужно будет сделать, будут минимальными. Откройте папку Controllers, а затем файл ValueControllers.cs
. Измените метод POST
чтобы он выглядел следующим образом:
[HttpPost] public HttpResponseMessage Post([FromBody]string value) { var product = JsonConvert.DeserializeObject<Product>(value); //ecommerce processing return new HttpResponseMessage(HttpStatusCode.NotAcceptable); }
value
параметра является JSON, отправленный с нашего веб-сайта. Этот JSON десериализуется в класс с помощью JsonConvert, для которого мы вскоре добавим ссылку. Оттуда мы можем сделать все необходимое для завершения транзакции электронной торговли.
Поскольку это всего лишь фиктивное решение, мы немедленно отправим обратно статус. Вот почему тип возвращаемого значения — HttpResponseMessage
. NotAcceptable
отправит обратно код состояния 406, который мы будем искать на нашем сайте как сбой, и предоставит пользователю соответствующее сообщение.
Чтобы добавить ссылку на JsonConvert
, мы добавим Nuget-пакет Newtonsoft.Json, как мы это делали в нашем веб-приложении. Щелкните правой кнопкой мыши узел «Ссылки» в обозревателе решений. Нажмите Управление пакетами Nuget. Поиск Newtonsoft.Json
. На скриншоте ниже видно, что я его уже добавил:
Если вы наведите курсор мыши на JsonConvert, вы увидите желтую лампочку на полях. Наведите указатель мыши на него, и вы получите подсказку для добавления правильного выражения using для класса JsonConvert
.
Теперь нам нужно создать наш класс продуктов. Помните, что приложение Web API только издевается над решением для электронной коммерции. Но это даст нам возможность увидеть, что представленный нами JSON фактически десериализован в класс. Вот что входит в класс Product
:
class Product { [JsonProperty("cardName")] public string cardName { get; set; } [JsonProperty("cardNumber")] public string cardNumber { get; set; } [JsonProperty("cardYear")] public string cardYear { get; set; } [JsonProperty("CardMonth")] public string CardMonth { get; set; } [JsonProperty("CardCv")] public string CardCv { get; set; } [JsonProperty("totalPrice")] public int totalPrice { get; set; } }
Установив точку останова в методе Post, мы можем увидеть, как выглядят наши связанные данные из веб-приложения:
MVC дает нам эту привязку бесплатно. Нам ничего не нужно для этого, кроме как убедиться, что свойства нашего класса совпадают со свойствами нашего метода.
Резюме
Мы расширили наш веб-сайт по урокам игры на гитаре, позволяя нашему артисту продавать уроки прямо со своего сайта. Используя простое решение, мы разместили список товаров, корзину и оформление заказа на одной странице. С помощью некоторых AngularJS мы смогли воспользоваться динамической функциональностью, чтобы обеспечить мгновенную обратную связь с пользователем.
В следующей статье мы создадим мобильное приложение полностью в Visual Studio. Цель приложения будет уведомлять пользователя о новых уроках. Используя платформу Cordova, мы можем использовать имеющиеся у нас знания веб-языков для написания полнофункционального мобильного приложения.