日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(2)--前端,以及前后端Session

發布時間:2025/4/5 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(2)--前端,以及前后端Session 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文:購物車Demo,前端使用AngularJS,后端使用ASP.NET Web API(2)--前端,以及前后端Session

?

chsakell分享了前端使用AngularJS,后端使用ASP.NET Web API的購物車案例,非常精彩,這里這里記錄下對此項目的理解。


文章:
http://chsakell.com/2015/01/31/angularjs-feat-web-api/
http://chsakell.com/2015/03/07/angularjs-feat-web-api-enable-session-state/

?

源碼:
https://github.com/chsakell/webapiangularjssecurity

?

本系列共三篇,本篇是第二篇。


購物車Demo,前端使用AngularJS,后端使用ASP.NET Web API(1)--后端
購物車Demo,前端使用AngularJS,后端使用ASP.NET Web API(2)--前端,以及前后端Session
購物車Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端驗證

?

HomeController用來展示主頁面,并接受前端傳來的Order的編號。

?

public calss HomeCOntroller : Controller {public ActionReuslt Index(){retun View();}public ActionResult ViewOrder(int id){using(var context = new SotreContext()){//這時候Order的導航屬性Gadgets還沒有加載出來呢var order = context.Orders.Find(id);//根據Order編號獲取中間表var gadgetOrders = context.GadgetOrders.Where(go => go.OrderID == id);foreach(GadgetOrder gadgetOrder in gadgetOrders){//加載中間表某個記錄中對應的導航屬性context.Entry(gadgetOrder).Reference(g => g.Gadget).Load();order.Gadgets.Add(gadgetOrder.Gadget);}return View(order);}} }

?

Home/Index.cshtml視圖。

?

<html ng-app="gadgetsStore">...<body ng-controller='gadgetStoreCtrl'><div ng-hide="checkoutComplete()"><div ng-show="showFilter()"><form><input type="text" ng-model="searchItem"></form></div><cart-details></cart-details></div><div ng-show="data.error" ng-cloak>{{data.error.status}}</div><ng-view /><script src="../../Scripts/angular.js" type="text/javascript"></script><script src="../../Scripts/angular-route.js" type="text/javascript"></script><script src="../../app/mainApp.js"></script><script src="../../app/controllers/gadgetsStore.js" type="text/javascript"></script><script src="../../app/filters/storeFilters.js" type="text/javascript"></script><script src="../../app/controllers/gadgetsControllers.js" type="text/javascript"></script><script src="../../app/components/cartCmp.js" type="text/javascript"></script><script src="../../app/controllers/checkoutController.js" type="text/javascript"></</body> </html>

?

以上,ng-hide="checkoutComplete()"決定著是否顯示所在div,ng-show="data.error" 決定是否顯示報錯,<ng-view />根據路由顯示不同視圖,ng-cloak用來避免在切換視圖時頁面的閃爍,<cart-details></cart-details>是自定義的directive,和angularjs有關的js文件放在頂部,applicaiton相關js文件放在其下面,在mainApp.js文件中坐落著一個頂級module名稱是gadgetStore,而頂級controller被放在了gadgetsStoreCtrl.js這個js文件中了。


最終的界面如下:

?

main.js 聲明頂級module,以及配置路由。

?

angular.module("gadgetsStore", ["storeFilters", "storeCart", "ngRoute"]).config(function($routeProvider){$routeProvider.when("/gadgets",{templateUrl: "app/views/gadgets.html"});$routeProvider.when("/checkout",{templateUrl: "app/views/checkout.html"});$routeProvider.when("/submitorder",{templateUrl: "app/views/submitOrder.html"});$routeProvider.when("/complete",{templateUrl: "app/views/orderSubmitted.html"});$routeProvider.otherwise({templateUrl: "app/views/gadgets.html"});});

?

storeFilters, storeCart是我們自定義的,這里注入進來。

?

有了gadgetsStore這個module,現在就為這個module添加controller等。

?

angular.module('gadgetsStore').constant('gadgetsUrl', 'http://localhost:8888/api/gadgets').constant('ordersUrl', 'http://localhost:8888/api/orders').constant('categoreisUrl', 'http://localhost:8888/api/categories').controller('gadgetStore', function($scope, $http, $location, gadgetsUrl, categoresUrl, ordersUrl, cart){//因為gadgetsStore依賴引用了storeCart,所以這里可以引用cart//這里的data被用在主視圖上,所以data的數據會被其它部分視圖共享// $scope.data.gadgets// scope.data.erro// $scope.data.categories// $scope.data.OrderLocation// $scope.data.OrderID// $scope.data.orderError$scope.data = {};$http.get(gadgetsUrl).success(function(data){$scope.data.gadgets = data;}).error(function(error){$scope.data.error = error;});$http.get(categoresUrl).success(function(data){$scope.data.categories = data;}).error(function(error){$scope.data.error = error;});$scope.sendOrder = function(shippingDetails){var order = angular.copy(shippingDetails);order.gadgets = cart.getProducts();$http.post(ordersUrl, order).success(function(data, status, headers, config){$scope.data.OrderLocation = headers('Location');$scope.data.OrderID = data.OrderID;cart.getProducts().length = 0;}).error(function(error){$scope.data.orderError = error;}).finally(function(){$location.path("/complete");});}$scope.showFilter = function(){return $location.path() == '';}$scope.checkoutComplete = function(){return $location.path() == '/complete';}});

?

以上,為gadgetsStore這個module定義了常量以及controller。把一些規定的uri定義成某個moudule的常量是很好的習慣。通過$location.path方法可以獲取或設置當前窗口的uri。

?

好了,頂級的module和頂級的controller有了,Gadget部分如何顯示呢?

?

根據路由$routeProvider.when("/gadgets",{templateUrl: "app/views/gadgets.html"}), Gadget的視圖被放在了app/views/gadgets.html中了,來看gadgets.html這個視圖。

?

<div ng-controller="gadgetsCtrl" ng-hide="data.error"><!--左側導航部分--><div><!--這里的selectCategory方法實際是把controller內部的一個變量selectedCategory設為null--><a ng-click="selectCategory()">Home</a><a ng-repeat="item in data.categoires | orderBy: 'CategoryID'" ng-click="selectCategory(item.CategoryID)" ng-class="getCategoryClass(item.CategoryID)">{{item.Name}}</a></div><!--右側Gadgets部分--><div><div ng-repeat="item in data.gadgets | filter: categoryFilterFn | filter: searchItem | range:selectedPage:pageSize">{{item.Name}}{{item.Price | currency}}<img ng-src="../../images/{{item.Images}}" />{{item.Description}}<a ng-click="addProductToCart(item)">Add To Cart</a></div><!--分頁部分--><div><a ng-repeat="page in data.gadgets | filter:categoryFilterFn | filter:searchItem | pageCount:pageSize" ng-click="selectPage($index + 1)" ng-class="getPageClass($index + 1)">{{$index + 1}}</a></div></div> </div>

?


以上,把視圖的來源交給了gadgetsCtrl這個controller, 這個controller也被定義在了gadgetsStore這個module中。

?

gadgetsCtr.js

?

angular.module("gadgetsStore").constant("gadgetsActiveClass", 'btn-primary').constant('gadgetsPageCount', 3).controller("gadgetsCtrl", function($scope, $filter, gadgetsActiveClass, gadgetsPageCount, cart){//存儲Category的主鍵CategoryIDvar selectedCategory = null;//這里是傳給range和pageCount過濾器的$scope.selectedPage = 1;$scope.pageSise = gadgetsPageCount;//實際就是未selectedPage這個變量賦新值$scope.selectPage = function(newPage){$scope.selectedPage = newPage;}//這里把Category的編號CategoryID傳了進來$scope.selecteCategory = function(newCategory){$selectedCategory = newCategory;$scope.selectedPage = 1; }//這里的product實際就是Gadget//過濾出Gadget的CategoryID和這里的selectedCateogory一致的那些Gadgets$scope.categoryFilterFn = fucntion(product){return selectedCategory == null || product.CategoryID == selectedCategory;}//category實際是Category的主鍵CategoryID$scope.getCategoryClass = function(category){return selectedCategory == category ? gadgetsActiveClass : "";}$scope.getPageClass = function(page){return $scope.selectedPage = page ? gadgetsActiveClass : "";}$scope.addProductToCart = function(product){cart.addProduct(product.GadgetID, product.Name, product.Price, product.CategoryID);}});

?

在顯示Gadget列表的時候,<div ng-repeat="item in data.gadgets | filter: categoryFilterFn | filter: searchItem | range:selectedPage:pageSize">,這里用到了一個自定的過濾器range,這個過濾器被定義在了storeFilters.js中。

?

var storeFilters = angular.module('storeFilters',[]);storeFitlers.filter("range", function($filter){return function(data, page, size){if(angular.isArray(data) && angular.isNumber(page) && angular.isNumber(size)){var start_index = (page - 1)*size;if(data.legnth < start_index){return [];} else {return $filter("limitTo")(data.splice(start_index), size);}} else{return data;}} });sortFilters.filter("pageCount", function(){return function(data, size){if(angular.isArray(data)){var result = [];for(var i = 0; i < Math.ceil(data.length/size); i++){ result.push(i);}} else {return data;}} });

?

再來看$routeProvider.when("/checkout",{templateUrl: "app/views/checkout.html"});這個路由,checkout.html這個部分視圖如下:

?

<div ng-controller = "cartDetailsController"><div ng-show="cartData.length==0">no item in the shopping cart</div><div ng-hide="cartData.length == 0">{{item.count}}{{item.Name}}{{item.Price | currency}}{{(item.Price * item.count) | currency}}<button ng-click="remove(item.GadgetID)"></button>{{total() | currency}}<a href="#">Continue shopping</a><a href="#/submitorder">Place order now</a></div> </div>

?

對應的界面如下:

?

?

cartDetailsController這個controller也被放在了頂級module里。如下:

?

?

angular.module("gadgetsStore").controller("cartDetailsController", function($scope, cart){$scope.cartData = cart.getProducts();$scope.total = function(){var total = 0;for(var i = 0; i < $scope.cartData.length;i++){total += ($scope.cartData[i].Price * $scope.cartData[i].count);}return total;}$scope.remove = function(id){cart.removeProduct(id);}});

?

我們注意到,我們已經在多個地方注入cart這個服務 ,這個自定義的服務可以以factory的方式來創建,如果要用這個cart服務,它所在的module就要被其它module所引用。下面來創建cart服務:

?

var storeCart = angular.module('storeCart',[]);storeCart.factory('cart', function(){var cartData = [];return {addProduct: function(id, name, price, category){//用來標記是否已經向購物車里加了產品var addedToExistingItem = false;for(var i=0; i < cartData.length;i++){if(cartData[i].GadgetID == id){cartData[i].count++;addedToExistingItem = true;break;}}if(!addedToExistingItem){cartData.push({count:1, GadgetID: id, Price: price, Name: name, CategoryID:category});}},removeProduct: function(id){for(var i = 0; i < cartData.legnth; i++){if(cartData[i].GadgetID == id){cartData.splice(i, 1);break;}}},getProducts:function(){return cartData;}}; });

?

關于購物車部分,我們還記得,在主視圖用了<cart-details></cart-details>這個自定義的directive,實際也是在storeCart這個module中定義的。

?

sortCart.directive("cartDetails", function(cart){return {restrict: "E",templateUrl: "app/components.cartDetails.html",controller: function($scope){var cartData = cart.getProducts();$scope.total = function(){var total =0;for(var i = 0; i < cartData.legnth; i++){total += (cartData[i].Price * cartData[i].count);}return total;}$scope.itemCount = function(){var total = 0;for(var i = 0; i < cartData.length; i++){total += cartData[i].count;}return total;}}}; });

?

以上,對應的視圖為:

?

Your cart: {{itemCount()}} items {total() | currency} <a href="#/checkout">Checkout</a>

?

在顯示購物車明細的時候,給出了提交訂單的鏈接:

<a href="#/submitorder">Place order now</a>

?

根據路由$routeProvider.when("/submitorder",{templateUrl: "app/views/submitOrder.html"}),是會加載app/views/submitOrder.html部分視圖,界面如下:

?

?

對應的html為:

?

<form name="shippingForm" novalidate><input name="companyName" ng-model="data.shipping.CompanyName" required /><span ng-show="shippingForm.companyName.$error.required"></span><input name="name" ng-model="data.shipping.OwnerName" required /><span ng-show="shippingorm.name.$error.required"></span>...<button ng-disabled="shippingForm.$invalid" ng-click="sendOrder(data.shipping)">Complete Order</button> </form>

?

sendOrder被定義在了頂級module中:

?

$scope.sendOrder = function (shippingDetails) {var order = angular.copy(shippingDetails);order.gadgets = cart.getProducts();$http.post(ordersUrl, order).success(function (data, status, headers, config) {$scope.data.OrderLocation = headers('Location');$scope.data.OrderID = data.OrderID;cart.getProducts().length = 0;}).error(function (error) {$scope.data.orderError = error;}).finally(function () {$location.path("/complete");});}

?

/complete會路由到$routeProvider.when("/complete",{templateUrl: "app/views/orderSubmitted.html"}), app/views/orderSubmitted.html部分視圖如下:

?

?

其html部分為:

?

<div ng-show="data.orderError">{{data.orderError.status}}the order could not be placed, <a href="#/submitorder">click here to try again</a> </div> <div ng-hide="data.orderError">{{data.OrderID}}<a href="#">Back to gadgets</a><a href="{{data.OrderLocation}}">View Order</a> </div>

?

■ 實現購物車的Session

?

現在為止,還存在的問題是:當刷新頁面的時候,購物車內的產品就會消失,即還么有Session機制。

?

與ASP.NET Web API路由相關的HttpControllerRouteHandler, HttpControllerHandler, IRequireSessionState。

?

首先一個繼承內置的HttpControllerHandler,并實現內置的IRequiresSessionState接口。

?

public class SessionEnabledControllerHandler : HttpControllerHandler, IRequiresSessionState {public SessionEnabledControllerHandler(RouteData routeData): base(routeData){ } }

?

然后實現一個內置HttpControllerRouteHandler的繼承類。

?

public class SessionEnabledHttpControllerRouteHandler : HttpControllerRouteHandler {protected override IHttpHandler GetHttpHandler(RequestContext requestContext){return new SessionEnabledControllerHandler(requestContext.RouteData);} }

?

注釋掉WebApiConfig.cs中的代碼:

?

public static class WebApiConfig {public static void Register(HttpConfiguration config){// Web API configuration and services// Web API routes config.MapHttpAttributeRoutes();// Moved to RouteConfig.cs to enable Session/*config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional });*/} }

?

在RouteConfig中配置如下:

?

public class RouteConfig {public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");#region Web API Routes// Web API Session Enabled Route Configurations routes.MapHttpRoute(name: "SessionsRoute",routeTemplate: "api/sessions/{controller}/{id}",defaults: new { id = RouteParameter.Optional }).RouteHandler = new SessionEnabledHttpControllerRouteHandler(); ;// Web API Stateless Route Configurations routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional });#endregion#region MVC Routesroutes.MapRoute(name: "Default",url: "{controller}/{action}/{id}",defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });#endregion} }

?

以上,需要引用System.Web.Http。

?

現在,如果希望ItemsController中使用Session,那就這樣請求:

http://localhost:61691/api/sessions/items

?

如果不想用Session,那就這樣請求:

http://localhost:61691/api/items

?

現在,在前端,向購物車添加產品相關代碼為:

?

addProduct: function (id, name, price, category) {var addedToExistingItem = false;for (var i = 0; i < cartData.length; i++) {if (cartData[i].GadgetID == id) {cartData[i].count++;addedToExistingItem = true;break;}}if (!addedToExistingItem) {cartData.push({count: 1, GadgetID: id, Price: price, Name: name, CategoryID: category});} }

?

類似地,創建一個模型:

?

public class CartItem {public int Count { get; set; }public int GadgetID { get; set; }public decimal Price { get; set; }public string Name { get; set; }public int CategoryID { get; set; } }

?

對應的控制器為:

?

public class TempOrdersController : ApiController {//get api/TempOrderspublic List<CartItem> GetTempOrders(){List<CartItem> cartItems = null;if(System.Web.HttpContext.Current.Session["Cart"] != null){cartItems = (List<CartItem>)System.Web.HttpContext.Current.Session["Cart"];}return cartItems;}//post api/TempOrders [HttpPost]public HttpResponseMessage SaveOrder(List<CarItem> cartItems){if (!ModelState.IsValid){return new HttpResponseMessage(HttpStatusCode.BadRequest);}System.Web.HttpContext.Current.Session["Cart"] = cartItems;return new HttpResponseMessage(HttpStatusCode.OK);} }

?

再回到前端,首先在gadgetsStore這個頂級module中增加有關緩存API的uri常量。

?

angular.module('gadgetsStore').constant('gadgetsUrl', 'http://localhost:61691/api/gadgets').constant('ordersUrl', 'http://localhost:61691/api/orders').constant('categoriesUrl', 'http://localhost:61691/api/categories').constant('tempOrdersUrl', 'http://localhost:61691/api/sessions/temporders').controller('gadgetStoreCtrl', function ($scope, $http, $location, gadgetsUrl, categoriesUrl, ordersUrl, tempOrdersUrl, cart) { // Code omitted

?

重新定義cart這個服務:

?

storeCart.factory('cart', function(){var cartData = [];return {addProduct: function(id, name, price, category){var addedToExistingItem = false;for(var i = 0; i < cartData.length; i++){if(cartData[i].GadgetID == id){cartData[i].count++;addedToExistingItem = true;break;}}if(!addedToExistingItem){cartData.push({count:1, GadgetID: id, Price: price, Name: name, Category: category});}},removeProduct: fucntion(id){for(var i = 0; i < cartData.length; i++){if(cartData[i].GadgetID == id){cartData.splice(i, 1);break;}}},getProducts: fucntion(){return cartData;},pushItem: function(item){cartData.push({count: item.Count, GadgetID:item.GadgetID, Price: Item.Price, Name: item.Name, CategoryID: item.CategoryID})}}; });

?


為了在頁面每次刷新的時候保證Session的狀態,在主module中添加如下方法:

?

//用來把每次更新保存到后端的Session中 $scope.saveOrder = function () {var currentProducts = cart.getProducts();$http.post(tempOrdersUrl, currentProducts).success(function (data, status, headers, config) {}).error(function (error) {}).finally(function () {}); }//用來每次刷新向后端Session要數據 $scope.checkSessionGadgets = function(){$http.get(tempOrdersUrl).success(function(data){if(data){for(var i = 0; i < data.length; i++){var item = data[i];cart.pushItem(item);}}}).error(function(error){console.log('error checking session: ' + error) ;}); }

?

然后checkSessionGadgets這個方法就要被運用到主視圖上去,當頁面每次加載的時候調用它。

?

<body ng-controller='gadgetStoreCtrl' class="container" ng-init="checkSessionGadgets()">

?

每次向購車添加的時候需要重新更新后端的Session狀態。

?

$scope.addProductToCart = function (product) {cart.addProduct(product.GadgetID, product.Name, product.Price, product.CategoryID);$scope.saveOrder(); }

?

每次從購物車一處的時候需要重新更新后端的Session狀態。

?

$scope.remove = function (id) {cart.removeProduct(id);$scope.saveOrder(); }

?

在用戶提交訂單的時候,需要一出購物車內的產品,再更新后端的Session狀態。

?

$scope.sendOrder = function (shippingDetails) {var order = angular.copy(shippingDetails);order.gadgets = cart.getProducts();$http.post(ordersUrl, order).success(function (data, status, headers, config) {$scope.data.OrderLocation = headers('Location');$scope.data.OrderID = data.OrderID;cart.getProducts().length = 0;$scope.saveOrder();}).error(function (error) {$scope.data.orderError = error;}).finally(function () {$location.path("/complete");}); }

?

待續~~

?

總結

以上是生活随笔為你收集整理的购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(2)--前端,以及前后端Session的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。