Step by step create a simple MVC e-commerce website BooksStore (1), mvcbooksstore

Source: Internet
Author: User

Step by step create a simple MVC e-commerce website BooksStore (1), mvcbooksstore

Build a simple MVC e-commerce website step by step-BooksStore (1)

GitHub address: https://github.com/liqingwen2015/Wen.BooksStore

Building a simple MVC e-commerce website step by step-BooksStore (I)

Building a simple MVC e-commerce website step by step-BooksStore (II)

Building a simple MVC e-commerce website step by step-BooksStore (III)

Building a simple MVC e-commerce website step by step-BooksStore (4)

Introduction

The main functions and knowledge points are as follows:

Category, product browsing, shopping cart, settlement, CRUD (add, delete, modify, and query) manage, mail, pagination, model binding, authentication filters, and unit tests (four articles are expected, Friday, Wednesday, and Tuesday ).

[Note] the project is developed using VS2015 + C #6. If you have any questions, please post them in the message area. Also, the page looks ugly. Sorry.

Directory

  • Create a project Architecture
  • Create a domain model entity
  • Create unit test
  • Create controllers and views
  • Create a page
  • Add Style

1. Create a project Architecture

1. Create a solution "BooksStore" and add the following items:

BooksStore. domain: Class Library, which stores the Domain model and logic. Use EF; BooksStore. webUI: A Web MVC application that stores views and controllers and acts as the display layer. Ninject is used as the DI container; BoosStore. unitTest: unit test, which tests the two items above.

Web MVC is an empty MVC project:

2. Add a project reference (NuGet is required ):

This is the class library and project to be referenced by different projects.

3. Set DI container

We use Ninject to create a custom factory. A class named NinjectControllerFactory inherits defacontrocontrollerfactory (default controller factory ). You can also add custom code to change the default behavior of the MVC framework.

AddBindings () to add the binding method. leave it blank first.

Public class initialize: DefaultControllerFactory {private readonly IKernel _ kernel; public construct () {_ kernel = new StandardKernel (); AddBindings ();} protected override IController GetControllerInstance, type controllerType) {return controllerType = null? Null: (IController) _ kernel. Get (controllerType);} // <summary> // Add a binding // </summary> private void AddBindings (){}}

4. Add a line of code in Global. asax to instruct MVC to use the newly created class to create the Controller object.

ControllerBuilder. Current. SetControllerFactory (new NinjectControllerFactory ());

public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() {  AreaRegistration.RegisterAllAreas();  RouteConfig.RegisterRoutes(RouteTable.Routes);  ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); } }

Ii. Create a domain model entity

1. Create an object class named Book in the graph.

Public class Book {// <summary> // Id /// </summary> public int Id {get; set ;} /// <summary> /// Name /// </summary> public string Name {get; set ;} /// <summary> /// Description /// </summary> public string Description {get; set ;} /// <summary> /// Price /// </summary> public decimal Price {get; set ;} /// <summary> /// Category /// </summary> public string Category {get; set ;}}

After an object is created, we should create a "Database" to operate the object, and this persistence logic operation should also be isolated from the domain model.

2. Define an interface IbookRepository and create a folder named Abstract in the root directory. As the name suggests, Abstract classes such as interfaces should be placed.

public interface IBookRepository { IQueryable<Book> Books { get; } }

Through this interface, we can obtain information about the corresponding class, without having to worry about how the data is stored and the storage location. This is the essence of the Repository mode.

3. Next, we need to operate the database. We need to use a simple EF (ORM Object Relational Model) to operate the database, so we need to download the EF class library through Nuget.

4. Because the interface class was previously defined, we should then define the class to implement this interface.

After installation, create a folder named Concrete to store the instance.

Create an EfDbContext class derived from DbContext, which automatically defines an attribute for each table in the database to be used. This attribute is named Books and specifies the table name. DbSet <Book> indicates the table model of the Book object. The Book object is equivalent to the row (record) in the Books table ).

 public class EfDbContext : DbContext { public DbSet<Book> Books { get; set; } }

Create an EfBookRepository repository class, which implements the IBookRepository interface and uses the EfDbContext context object created above, including the specific method definition.

public class EfBookRepository : IBookRepository { private readonly EfDbContext _context = new EfDbContext(); public IQueryable<Book> Books => _context.Books; }

5. Now, we only need to create a new table in the database.

CREATE TABLE Book( Id INT IDENTITY PRIMARY KEY, Name NVARCHAR(100), Description NVARCHAR(MAX), Price DECIMAL, Category NVARCHAR(50))

Insert test data:

Insert into dbo. book (Name, Description, Price, Category) VALUES (n'c # from entry to Master', -- Name-nvarchar (100) n'good book-C # from entry to Master', -- Description-nvarchar (max), -- Price-decimal n '. NET '-- Category-nvarchar (50) insert into dbo. book (Name, Description, Price, Category) VALUES (n' ASP. NET from entry to proficient ', -- Name-nvarchar (100) n' good book-ASP. NET from entry to proficient ', -- Description-nvarchar (max), -- Price-decimal n '. NET '-- Category-nvarchar (50) insert into dbo. book (Name, Description, Price, Category) VALUES (n'multithreading from entry to Master', -- Name-nvarchar (100) n' good Book-multithreading from entry to Master ', -- Description-nvarchar (max), -- Price-decimal n '. NET '-- Category-nvarchar (50) insert into dbo. book (Name, Description, Price, Category) VALUES (n'java from getting started to give up ', -- Name-nvarchar (100) n' good Book-java from getting started to give up ', -- Description-nvarchar (max), -- Price-decimal N 'java' -- Category-nvarchar (50) insert into dbo. book (Name, Description, Price, Category) VALUES (n' SQL from getting started to abandon ', -- Name-nvarchar (100) n' good Book-SQL from getting started to abandon ', -- Description-nvarchar (max), -- Price-decimal N 'SQL' -- Category-nvarchar (50) INSERT INTO dbo. book (Name, Description, Price, Category) VALUES (n' SQL from getting started to output', -- Name-nvarchar (100) n' good Book-SQL from getting started to output ', -- Description-nvarchar (max), -- Price-decimal N 'SQL' -- Category-nvarchar (50) INSERT INTO dbo. book (Name, Description, Price, Category) VALUES (n'php from getting started to output', -- Name-nvarchar (100) n' good Book-php from getting started to output ', -- Description-nvarchar (max), -- Price-decimal N 'php' -- Category-nvarchar (50 ))

Test Data

Because I want the Table name to be Book instead of Books, I added the feature [Table ("Book")] to the previous Book class:

3. Create a unit test

1. after the push operation is completed, you may want to display it on the Interface immediately. Don't worry. First, use a unit test to check whether the operations on the database are normal. By simply reading the data, check whether the connection is successful.

2. ef class library (Nuget) must also be introduced for unit testing ).

3. after installation, an app is generated. in the config configuration file, you need to add an additional line of connection string (this information must also be added in subsequent Web UI projects, otherwise the corresponding error message will be prompted ).

<connectionStrings> <add name="EfDbContext" connectionString="server=.;database=TestDb;uid=sa;pwd=123" providerName="System.Data.SqlClient"/> </connectionStrings>

4. when all the preparations are ready, you should fill in the test method. Because I have inserted 7 data records, here I will judge whether the number of rows read from the database is 7:

[TestMethod] public void BooksCountTest() {  var bookRepository=new EfBookRepository();  var books = bookRepository.Books;  Assert.AreEqual(books.Count(),7); }

5. Right-click the method body and you will see a "run test" option. Then you can click it:

From this symbol, we can see that it is successful!

Next, we will officially display the information we want from the page.

4. Create controllers and views

1. Create an empty Controller: BookController:

2. We need to customize a Details Method for subsequent interaction with the interface.

Public class BookController: Controller {private readonly IBookRepository _ bookRepository; public BookController (IBookRepository bookRepository) {_ bookRepository = bookRepository ;} /// <summary> /// Details /// </summary> /// <returns> </returns> public ActionResult Details () {return View (_ bookRepository. books );}}

3. Create a View.

4. Replace the contents of Details. cshtml with the following:

@model IEnumerable<Wen.BooksStore.Domain.Entities.Book>@{ ViewBag.Title = "Books";}@foreach (var item in Model){ <div> 

5. Change the default routing mechanism so that it will jump to the page by default.

6. note that the Ninject container is used and the IBookRepository parameter in the constructor In the controller needs to be parsed to indicate which object will be used to serve the interface, that is, you need to modify the AddBindings method:

7. The running effect is roughly as follows (because the CSS style is added, the display effect may be somewhat different), and the results are consistent.

5. Create a page

1. Add a PagingInfo. cs paging information class in the Models folder.

/// <Summary> /// page information /// </summary> public class PagingInfo {/// <summary> /// total /// </summary> public int TotalItems {get; set ;}//< summary> /// page capacity /// </summary> public int PageSize {get; set ;} /// <summary> /// current page /// </summary> public int PageIndex {get; set ;} /// <summary> /// total number of pages /// </summary> public int TotalPages => (int) Math. ceiling (decimal) TotalItems/PageSize );}

2. added an Html helpers folder to store an extension method based on the Html Help class:

Public static class PagingHelper {// <summary> /// paging // </summary> /// <param name = "helper"> </param> /// <param name = "pagingInfo"> </param> // <param name = "func"> </param> // <returns> </returns> public static MvcHtmlString pageLinks (this HtmlHelper helper, pagingInfo pagingInfo, Func <int, string> func) {var sb = new StringBuilder (); for (var I = 1; I <= pagingInfo. totalPages; I ++) {// create <a> label var tagBuilder = new TagBuilder ("a"); // Add the tagBuilder feature. mergeAttribute ("href", func (I); // Add the value tagBuilder. innerHtml = I. toString (); if (I = pagingInfo. pageIndex) {tagBuilder. addCssClass ("selected");} sb. append (tagBuilder);} return MvcHtmlString. create (sb. toString ());}}

3. After adding the namespace, you need to add it to the configuration file.

4. Now you need to modify the code in the BookController. cs controller and add the new view model class BookDetailsViewModels. cs to inherit the previous paging class.

public class BookDetailsViewModels : PagingInfo { public IEnumerable<Book> Books { get; set; } }

The modified controller code:

Public class BookController: Controller {private readonly IBookRepository _ bookRepository; public int PageSize = 5; public BookController (IBookRepository bookRepository) {_ bookRepository = bookRepository ;} /// <summary> /// details /// </summary> /// <param name = "pageIndex"> </param> /// <returns> </ returns> public ActionResult Details (int pageIndex = 1) {var model = new BookDetailsViewModels () {Books = _ bookRepository. books. orderBy (x => x. id ). skip (pageIndex-1) * PageSize ). take (PageSize), PageSize = PageSize, PageIndex = pageIndex, TotalItems = _ bookRepository. books. count ()}; return View (model );}}

5. After the view model is modified, the corresponding view page also needs to be modified.

@model Wen.BooksStore.WebUI.Models.BookDetailsViewModels@{ ViewBag.Title = "Books";}@foreach (var item in Model.Books){ <div> 

6. Add a style

1. the style of the page is simply designed as three sections. The top is the title and the left sidebar is the category. The main module displays the specific content.

Now we want to create a file _ ViewStart. cshtml under the Views folder, and then create a Shared folder and file _ Layout. cshtml.

2. _ Layout. cshtml this is the Layout page. When the code is executed to @ RenderBody (), it is responsible for rendering the content of the previous Details. cshtml:

<! DOCTYPE html> 

_ ViewStart. cshtml this file indicates that the default layout page is the View File:

@{ Layout = "~/Views/Shared/_Layout.cshtml";}

3. Add a folder named Contents under the root directory of the website to store CSS.

body {}#header, #content, #sideBar { display: block;}#header { background-color: green; border-bottom: 2px solid #111; color: White;}#header, .title { font-size: 1.5em; padding: .5em;}#sideBar { float: left; width: 8em; padding: .3em;}#content { border-left: 2px solid gray; margin-left: 10em; padding: 1em;}.pager { text-align: right; padding: .5em 0 0 0; margin-top: 1em;} .pager A { font-size: 1.1em; color: #666; padding: 0 .4em 0 .4em; } .pager A:hover {  background-color: Silver; } .pager A.selected {  background-color: #353535;  color: White; }

Now, the page has an effect, and the basic interface is displayed.

GitHub address: https://github.com/liqingwen2015/Wen.BooksStore

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.