逐步创建ASP.NET Core 2.2应用程序

目录

介绍

条件

机器配置

期望

好开始

创建一个新的ASP.NET Core 2.2应用程序

插入中间件和服务

创建模型和存储库类

添加控制器

添加视图

改进包括HTML标记

介绍布局模板

使用_ViewStart进一步细化视图

介绍ViewModel

使用Bootstrap改善视图的观感

使用EF Core获取真实数据

创建数据库

添加导航

添加表单以请求注释

保护应用程序配置标识

添加身份验证支持

添加授权支持


介绍

本文将从零开始介绍使用ASP.NET Core 2.2创建ASP.NET Core应用程序的过程,通过利用包管理器,EF CoreIdentity APIRazor类库等的功能。因此,本文将重点介绍实现部分,而不是更为理论化。在任何需要的地方,我也会对概念部分进行一些说明。

条件

熟悉C#以及网页设计及其概念的工作知识。

机器配置

本演练中使用的计算机配置是带有.NET Core开发工具/ SDKVisual Studio 2017。确保至少安装了.NET Core 2.2

期望

在本文结束时,读者将拥有一个用于曲奇饼干存储的ASP.NET Core网站的工作模型。

好开始

背景已经准备好了,我们可以开始了。让我们从逐步创建应用程序开始。

创建一个新的ASP.NET Core 2.2应用程序

让我们打开Visual Studio。转到文件菜单,选择新建,然后选择项目。在选择Web作为类别时,您将看到以下对话框:

单击确定后,您将看到以下对话框,您可以在其中重新验证所选的ASP.NET Core版本。作为一个学习者,最好使用Empty模板,因为我们可以自己处理每一件事,而不是依赖于自动生成的代码。选择Empty并继续。

成功创建项目后,您可以看到依赖项节点添加了所需的引用,如下所示:

在这里,让我们删除appsettings.json文件,因为我们将在稍后创建自己的文件,并在项目下添加一个名为wwwroot的新文件夹。一旦wwwroot文件夹被创建,你可以看到,文件夹图标改变。这是一个特殊的文件夹,存储所有静态文件(css,图像文件,JavaScript文件等),并直接映射到网站URL

插入中间件和服务

让我们从Startup类开始。此类包含两个非常重要的方法命名为ConfigureServicesConfigure。这两种方法都由ASP.NET Core 自动调用。使用ConfigureServices,我们可以使用IServiceCollection将服务添加到依赖注入容器中。那么,我们来添加MVC服务,如下所示:

public void ConfigureServices(IServiceCollection services)
{
   services.AddMvc();
}

接下来是ConfigureServices方法,该方法用于配置中间件管道,其中包含将为我们的请求提供服务的组件。以下是插入所需中间件的初始代码:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
 app.UseDeveloperExceptionPage();
 app.UseStatusCodePages();
 app.UseStaticFiles();
 app.UseMvcWithDefaultRoute();
}

请注意,添加中间件的顺序非常重要。现在我们已经完成了为我们的应用程序奠定基础的基础工作,让我们继续并设置其他有用的组件。

创建模型和存储库类

让我们首先在解决方案下创建一个Models文件夹,并在其下面命名一个Cookie类。

public class Cookie
{
    public int Id {get;set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string ImageURL { get; set; }
    public bool IsCookieOfTheDay { get; set; }
}

现在使用两个初始方法快速创建一个名称在同一文件夹下的IRepository接口,如下所示:

public interface IRepository
{
    IEnumerable<cookie> GetAllCookies();
    Cookie GetCookieById(int id);
}

下一个任务是创建一些虚拟数据,我们可以使用它们来验证我们的应用程序是否按预期工作。这是IRepository接口的实现:

public class MockRepository : IRepository
{
    private List<cookie> _cookies;
    public MockRepository()
    {
        if (_cookies == null)
        {
            InitializeRepository();
        }
    }

    private void InitializeRepository()
    {
        _cookies = new List<cookie>
        {
            new Cookie
            { Id=1,Name="Raspberry", Price=110, 
              TinyDescription="Dark chocolate overloaded",                   
                    FullDescription ="This is one of the best ever 
                    soft and chewy cookie and also been awarded as the 
                    best cookie several times.", IsCookieOfTheDay=false,
                    ImageUrl ="\\Images\\1.png"},
                new Cookie{ Id=2, Name="Nuts Overloaded", 
                Price=100, TinyDescription="Truely healthy",
                    FullDescription ="This cookie is fully loaded 
                    with nuts of various types and contains 
                    nice amount of peanut butter.", IsCookieOfTheDay=true,
                    ImageUrl ="\\Images\\2.png"},
                new Cookie{Id=3, Name="Chocolate",
                Price=70,TinyDescription="Amazingly fruity",
                    FullDescription ="This cookie is best suited 
                    for the chocolate lovers. It's less sweet and gives 
                    very elegant taste.", IsCookieOfTheDay=false,
                    ImageUrl ="\\Images\\3.png"},
                new Cookie{Id=3, Name="Delicious Oatmeal",Price=50,
                TinyDescription="Truely healthy",
                    FullDescription ="This is one of the most moist and 
                    flavourful cookie, which can make anyone's mood happy.", 
                    IsCookieOfTheDay=false,
                    ImageUrl ="\\Images\\4.png"},
            };
        }
        
    public Cookie GetCookie(int id)
    {
        return _cookies.FirstOrDefault(x => x.Id == id);
    }

    public IEnumerable<cookie> GetCookies()
    {
        return _cookies;
    }
}

让我们在ConfigureServices方法中使用依赖注入容器注册这个IRepository,如下所示:

services.AddTransient<irepository, mockrepository="">(); // get me new instance every time

添加控制器

让我们在项目下创建一个名为Controllers的新文件夹,并在其中添加一个名为Home的空控制器。简而言之,控制器负责在模型的帮助下,通过调用方法,根据用户的请求创建响应。就MVC而言,这种方法通常被称为动作方法。下面是在控制器内部使用的IRepository代码,用于从模型中获取数据。

public class HomeController : Controller
{
    private readonly IRepository _repository;
    public HomeController(IRepository repository)
    {
        _repository = repository;
    }

    public IActionResult Index()
    {
        return View();
    }
}

添加视图

到目前为止,我们已经完成了基本的模型和控制器。所以,唯一悬而未决的是ViewASP.NET Core 2.2中,视图可以有两种类型_常规/普通视图和强类型视图。但在大多数情况下,需要强类型视图。在这里,我们将使用Razor

因此,让我们在项目下创建一个名为Views的新文件夹以及一个名为Home的子文件夹。右键单击Home文件夹并添加新项Razor View。成功添加View后,您会注意到在Home文件夹下添加了一个名为Index.cshtml的新文件。

现在是时候验证视图和控制器是否正确绑定并能够进行通信。为了验证这个目的,让我们为页面添加一些标题,我们将使用控制器类ViewBag传递该标题的值。同样,我们还将显示有关曲奇饼干的一些信息。以下是更新后的HomeController方法:

public IActionResult Index()
{
    ViewBag.Title = "Cookies and only Cookies";
    var cookies = _repository.GetAllCookies().OrderByDescending(x=>x.Price);
    return View(cookies);
}

接下来是更新视图以读取此title值。这是以下代码:

现在,如果您运行应用程序,您将能够看到以下输出:

改进包括HTML标记

在上面的代码片段中,我们看到编写完整的HTML标记以显示页面。现在如果我们有很多view怎么办?我们是否要为每个页面重复此HTML代码?

当然不是。这就是模板。我们可以创建一个模板并在所有视图中引用该模板。这样做还可以减少单个视图中的代码量。很明显,如果要在许多组件之间共享某些内容,则必须将其保存在共享位置,并且这是作为MVC设计的一部分引入共享文件夹的地方。

介绍布局模板

Views文件夹下添加一个新文件夹,并将其命名为Shared。右键单击Shared文件夹并添加一个新项Razor Layout。这个新添加项目的默认名称是_Layout.cshtml,如下所示:

如果仔细观察,您可能会注意到_Layout.cshtml和我们的视图包含大多数常用代码。因此,是时候将_Layout.cshtml集成到我们的视图中,在集成之后,我们的视图将仅包含以下代码:

使用_ViewStart进一步细化视图

我们通过减少视图文件中的代码行做得非常好,但仍有一些工作要做。同样,我们在视图中集成的布局将针对每个视图进行复制。我们还可以摆脱这种重复吗?当然,是的。

让我们在Views文件夹下添加另一个新项目Razor View Start,默认名称为_ViewStart.cshtml。此文件附带默认代码,如下所示,并自动调用:

@{
    Layout = "_Layout";
}

现在您可以看到此文件已经为我们插入Layout,这意味着我们视图中的代码行进一步减少到几行,如下所示:

您可以重新运行您的应用程序并验证它是否按预期工作。

介绍ViewModel

您必须注意到我们的视图是从多个路径获取数据。那么,为什么我们不能摆脱这个并创建一个单一的实体,这将是我们view的来源。让我们来试试吧。

我们将在项目下添加一个名为ViewModels的新文件夹,并在其下面命名一个新类HomeViewModel。这个ViewModel类将作为我们Home视图的数据源。截至目前,我们将采用如下所示的最小字段:

public class HomeViewModel
{
    public string Title { get; set; }
    public List<cookie> Cookies { get; set; }
}

因此,我们必须更新我们HomeController内的的Index方法,如下所示:

public IActionResult Index()
{
    HomeViewModel viewModel = new HomeViewModel
    {
            Title = "Cookies and only Cookies",
            Cookies = _repository.GetAllCookies().OrderByDescending(x => x.Price).ToList()
    };
           
    return View(viewModel);
}

最后,让我们用HomeViewModel的引用更新View,如下所示:

重新验证输出,它应该仍然是相同的。

使用Bootstrap改善视图的观感

这可以使用称为Bootstrap的客户端程序包来完成。根据Visual Studio的版本和更新,可以选择任何包管理器,如BowerLibrary ManagerLibMan)等。在这里,我将使用库管理器(Library Manager),因为我的Visual Studio版本是15.8.5。让我们在项目级别添加新项目添加客户端库 ”,并提供详细信息,如下所示:

接下来是将图像添加到我们的应用程序。为此,我们必须在wwwroot下创建另一个名为Images文件夹。

然后我们必须在我们的应用程序中添加一个样式表,为此,必须在wwwroot下添加一个名为content的新文件夹,在其中,我们必须创建一个名为site.css的样式表。完成后,我们可以添加以下基本样式:

body {
    padding-top:50px;
    padding-bottom:20px;
    background-image: url();
    background-repeat: repeat;
}

.body-content{
    padding-left: 15px;
    padding-right: 15px;
}

最后,我们必须使用<Link>cssbootstrap关联到我们的_Layout页面,如下所示:

接下来是更新视图文件以适应bootstrap。以下是完整的代码:

如果一切顺利,您将在运行应用程序时看到以下网页:

接下来是将关联真实数据库与我们的应用程序。

使用EF Core获取真实数据

EF Core是一个支持ASP.NET Core等跨平台功能的ORM。值得一提的是,截至目前,EF Core仅支持Code-First方法。以下是将EF与我们的应用程序完全集成时需要注意的步骤:

  • 创建实体类
  • 创建数据库上下文
  • 设置连接字符串
  • 更改应用程序配置

让我们在Models文件夹下创建一个名为DatabaseContext的新类,并添加下面的代码:

public class DatabaseContext:DbContext
{
    public DatabaseContext(DbContextOptions<databasecontext> options):base(options)
    {

    }
    public DbSet<cookie> Cookies { get; set; }
}

DataContext在将我们的应用程序连接到实际数据库中起着至关重要的作用。直到现在,我们使用MockRepository类使用模拟值。所以,是时候在Models文件夹下创建一个名为Repository的实际类,其包含如下的代码:

public class Repository:IRepository
{
    private readonly DatabaseContext _dbContext;
    public Repository(DatabaseContext databaseContext)
    {
        _dbContext = databaseContext;
    }

    public Cookie GetCookie(int id)
    {
        return _dbContext.Cookies.FirstOrDefault(x => x.Id == id);
    }

    public IEnumerable<cookie> GetCookies()
    {
        return _dbContext.Cookies;
    }
}

接下来是设置连接字符串。希望大多数人都知道ASP.NET Core不再使用Web.Config文件,而是使用appsettings.json。因此,添加一个名为appsettings.json的新项应用程序设置文件并更新其中的连接字符串。我的代码看起来像这样:

{
  "ConnectionStrings": {
    "DefaultConnection": 
         "Server=(localdb)\\MSSQLLocalDB;Database=CookiesDataStore;
          Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

作为最后一步,我们必须在我们的应用程序中注册EF Core,这可以通过在Startup类上更新ConfigureServices()来完成,如下所示:

public class Startup
{
    public IConfiguration Configuration { get; set; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<databasecontext>(options => options.UseSqlServer
                     (Configuration.GetConnectionString("DefaultConnection")));
        services.AddTransient<irepository, repository="">();
        services.AddMvc();
    }

        // This method gets called by the runtime. 
        // Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseDeveloperExceptionPage();
        app.UseStatusCodePages();
        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }
}

是时候构建代码并验证没有更多的编译错误。

创建数据库

为了在网页上查看内容,我们需要数据库中的数据。在这里,我们将使用包管理控制台和以下命令:

PM> add-migration CookiesDatabaseMigration
PM> update-database

要添加一些初始数据到数据库中,我们将在Models文件夹下创建一个名为DbInitializer的新类,其代码如下:

public static class DbInitializer
    {
        public static void Seed(DatabaseContext dbContext)
        {
            if (!dbContext.Cookies.Any())
            {
                dbContext.AddRange(
                    new Cookie
                    {                        
                        Name = "Choco Chips",
                        Price = 80,
                        TinyDescription = "Dark chocolate overloaded",
                        FullDescription = "This is one of the most moist 
                                           and flavourful cookie, 
                                           which can make anyone's mood happy.",
                        IsCookieOfTheDay = false,
                        ImageUrl = "\\Images\\Chocochip.png"
                    },
                    new Cookie
                    {
                        Name = "Nuts & Peanuts",
                        Price = 75,
                        TinyDescription = "Truely healthy",
                        FullDescription = "This cookie is fully loaded 
                                           with nuts of various types and 
                                           contain nice amount of peanut butter.",
                        IsCookieOfTheDay = true,
                        ImageUrl = "\\Images\\ChocolateChipWalnut.png"
                    },
                    new Cookie
                    {
                        Name = "Berries & Rasins",
                        Price = 50,
                        TinyDescription = "Amazingly fruity",
                        FullDescription = "This is one of the best ever soft 
                                           and chewy cookie and also been awarded 
                                           as the best cookie several times.",
                        IsCookieOfTheDay = false,
                        ImageUrl = "\\Images\\Nuts.png"
                    },
                    new Cookie
                    {
                        Name = "Coconut",
                        Price = 100,
                        TinyDescription = "Truely healthy",
                        FullDescription = "This cookie is best suited 
                                           for the nut lovers. It's less sweet and 
                                           gives very elegant taste.",
                        IsCookieOfTheDay = false,
                        ImageUrl = "\\Images\\Coconut.png"
                    }
                    );
            }
            dbContext.SaveChanges();
        }
    }

接下来是从Program类中调用DbInitializer,以下是相同的更新代码:

public static void Main(string[] args)
{
        var host = CreateWebHostBuilder(args).Build();
        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            try
            {
                var context = services.GetRequiredService<databasecontext>();
                DbInitializer.Seed(context);
            }
            catch (Exception ex)
            {
                // TODO
            }
        }

        host.Run();
}

现在快速运行应用程序,您将看到与以前相同的输出。

添加导航

作为导航的一部分,我们将创建一个详细信息页面,其中包含所选曲奇饼干的详细信息。要获取所选曲奇饼干的详细信息,必须在HomeController类中添加新方法,如下所示:

public IActionResult Details(int id)
{
    var cookie = _repository.GetCookie(id);
    return View(cookie);
}

当然,我们必须在HomeController中为此方法添加名称为Details.cshtml视图:

现在,我们想要从Index视图导航到Details视图。因此,我们将使用标记助手(tag helpers),如下所示:

最后一件事是在我们的首页上添加导航,这可以使用nav元素完成。以下是_Layout.cshtml的更新代码:

现在快速运行应用程序,您将能够在页面顶部看到链接:

添加表单以请求注释

现在,让我们添加一个表单,用户可以通过该表单为我们可爱的曲奇饼干提供反馈或评论。为此,我们必须添加一个名为Feedback的新模型实体, 如下所示:

public class Feedback
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Content { get; set; }
    public string Email { get; set; }
}

接下来是使用这个新实体更新数据库,可以通过运行add-migration命令来完成

PM> Add-Migration Feedback

让我们快速添加界面和方法,以保存反馈,代码如下所示:

public class FeedbackRepository: IFeedbackRepository
{
    private readonly DatabaseContext _dbContext;
    public FeedbackRepository(DatabaseContext context)
    {
        _dbContext = context;
    }
    public void AddFeedback(Feedback feedback)
    {
        _dbContext.Feedbacks.Add(feedback);
        _dbContext.SaveChanges();
    }
}

接下来是在ConfigureServices方法下使用依赖注入容器注册这个新接口:

public void ConfigureServices(IServiceCollection services)
{
    …
    services.AddTransient<ifeedbackrepository, feedbackrepository="">();
    services.AddMvc();
}

现在是时候对反馈功能进行UI更改了。以下是FeedbackController的代码及其视图:

public class FeedbackController : Controller
{
    private readonly IFeedbackRepository _feedbackRepository;
    public FeedbackController(IFeedbackRepository feedbackRepository)
    {
        _feedbackRepository = feedbackRepository;
    }

    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Index(Feedback feedback)
    {
        _feedbackRepository.AddFeedback(feedback);
        return View();
    }
}

接下来是在我们的应用程序首页上添加反馈链接,可以通过更新Layout页面来完成,如下所示:

Feedback点击后,导航将显示在下面的页面上:

保护应用程序配置标识

作为本节的一部分,我们将探索ASP.NET Core 标识API,并为了适应这一点,我们必须更新一些现有代码。让我们从DatabaseContext类开始。现在,我们不在继承DbContext,而是继承DatabaseContext类和IdentityDbContext<IdentityUser>,同时,我们必须通过添加app.UseAuthentication()来更新我们的中间件管道。

接下来,我们必须使用用户信息更新我们的数据库。因此,我们必须运行添加和更新迁移,如下所示:

PM> add-migration AuthenticationAdded
PM> update-database

成功执行后,您将看到在数据库中创建了以下表:

添加身份验证支持

为了向我们的应用程序添加身份验证功能,我们将使用ASP.NET Core附带的Razor类库提供的开箱即用功能。为此,右键单击项目并选择Add,然后选择New Scaffolded Item ...,选择Identity

在上面的操作后,我们将在下面的对话框中提及我们可以使用的所有视图。在这里,我将选择具有所需数据上下文的三个视图,如下所示:

public class IdentityHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices((context, services) => {
                services.AddDefaultIdentity<identityuser>(IdentityUser)
                .AddEntityFrameworkStores<databasecontext>(DatabaseContext);
            });
        }
    }

通过上面的代码,我们使用数据库上下文来保存身份信息。最后,我们必须在导航栏上提供链接,所以只需将登录内容插入到_Layout页面,<Partial>如下所示:

现在运行应用程序,您将看到两个额外的链接添加到导航栏。当然,您现在可以继续使用RegisterLogin功能。不是很酷吗?

添加授权支持

到此为止,我们已经提供了登录功能,但是如何限制任何用户使用某些网站功能,例如,只允许登录用户提交反馈。这里有授权的概念。让我们通过使用Authorize属性装饰我们的Feedback控制器来快速完成它,如下所示:

[Authorize]
public class FeedbackController : Controller
{
   ……         
}

我们已经完成了,是时候运行应用程序并验证所有内容。

希望您喜欢创建自己的ASP.NETCore应用程序,并了解所有基本概念。

 

原文地址:https://www.codeproject.com/Articles/5061469/Creating-ASP-NET-Core-2-2-Application-Step-by-Step

猜你喜欢

转载自blog.csdn.net/mzl87/article/details/90814694
今日推荐