技术开发 频道

visual studio 2012建立工程实战

  【IT168技术】随着2012年8月份,微软正式推出了visual studio 2012,其中asp.net mvc4和asp.net web api也正式与广大开发者见面了。其中asp.net mvc4比之前的版本有了不少新的改进特性,而asp.net web api也可以认为是微软推出的符合REST标准的API接口,大大方便了对REST的调用。本文以及后续的系列文章将通过实际例子,介绍如何搭配使用asp.net mvc4和asp.net web api,本文要求读者有一定的asp.net mvc基础或使用asp.net的基础阅读。

  步骤1 新建立工程

  在本文中,使用的是visual studio 2012 RTM版本和sql server 2012。其中本文的完整代码可以在https://github.com/jcreamer898/NetTutsMvcEf 中可以下载。 然后打开vs.net 2012,在文件――新建菜单中,选择如下图的新建立Internet Application。

visual studio 2012建立工程实战

  步骤2 使用Entitiy Framework

  在本文中,使用的是微软的Entity Framework去搭建项目的数据层。其中Entity Framework框架允许开发者先设计好对应的POJO类,然后会自动生成对应的数据库对应的表,并且能让开发者使用LINQ查询语言去查询数据库,这是十分方便的,关于Entity Framework的相关知识,请读者另行参考相关的资料学习。

  我们做的这个例子,是关于一个审核的应用,把这个实体类命名为Review,编写如下的代码:

  // Review.cs

public class Review
{
public int Id { get; set; }
[Required]
public string Content { get; set; }
[Required]
[StringLength(
128)]
public string Topic { get; set; }
[Required]
public string  Email { get; set; }
[Required]
public bool  IsAnonymous { get; set; }
public int CategoryId { get; set; }
public  virtual  Category Category { get; set; }
public  virtual  IEnumerable<Comment> Comments { get; set; }
}

  在上面的代码中,Review类有自己的id主键,而content属性则存放审核的内容,Topic属性存放的是审核的主体标题,比如一个餐厅的名称(或者任何组织的名称), IsAnonymous字段表示是否为匿名审核者。而Category类则指向目录的分类的一个实例引用,Comments也是一个代表一对多关系的评论集合。下面看下Comment类的设计,如下所示:

public class Comment
{
public int Id { get; set; }
[Required]
public string Content { get; set; }
[Required]
public string Email { get; set; }
[Required]
public bool IsAnonymous { get; set; }
public int ReviewId { get; set; }
public Review Review { get; set; }
}

  可以看到,Comment类中,通过ReviewId和Review对Review类进行了外键引用。最后看下category类,如下:

public class Category
{
public int Id { get; set; }
[Required]
[StringLength(
32)]
public string Name { get; set; }
}

  在上面的代码中,会看到使用了[Required]的注解,规定了在数据库中这些字段是不能为空的,并且在接下来的编程中,将会用到做验证的相关工作。

  为了要创建这些类的相应的数据表,需要创建一个DbContext的类,名为ReviewedContext,如下:

public class ReviewedContext : DbContext
{
public DbSet<Review> Reviews { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Comment> Comments { get; set; }
public ReviewedContext()
{
Configuration.ProxyCreationEnabled
= false;
}
}

  在这个类中,每一个属性都对应当生成数据库表时的对应数据表。而Configuration.ProxyCreationEnabled的含义为不允许使用代理去存取对象,这样速度会更加快。

  接下来,我们需要设置一个叫数据库初始器(initializer),它能确保当用户修改数据模型实体的时候,数据库中的数据表能跟随变化,否则的话,当开发者重新设计实体模型或对其进行修改后,则必须手工删除数据库中的表。目前,.net提供了一些不同类型的initializer给用户选择:

  DropCreateDatabaseAlways和DropCreateDatabaseIfModelChanges,我们这里选择后者,就是当模型变化时,自动通知数据库进行变更。

  DropCreateDatabaseAlways和DropCreateDatabaseIfModelChanges都有个不好的地方就是当模型变化时,会自动删除数据表并且数据。幸亏EF Code First框架提供了第三种方案:Migrations。这个新的特性将能在当数据模型变化时,并不会删除数据。

  下面是初始器的代码:

public class ReviewedContextInitializer
: DropCreateDatabaseIfModelChanges
<ReviewedContext>
{
protected override void Seed(ReviewedContext context)
{

}
}

  其中ReviewedContextInitializer重写了Seed方法,这能让我们往数据库中增加一些测试数据。现在,我们打开Global.asx文件,并且往Application_Start方法中增加如下代码:

  Database.SetInitializer(new ReviewedContextInitializer());

  接下来,我们需要从数据库中获得数据,并且我们会使用依赖注入去实现接下来的架构,而依赖注入相信大家应该不会陌生,这里我们使用Ninject这个开源的依赖注入框架(其地址为http://www.ninject.org/)。

  简单来说,依赖注入的核心思想主要是对类之间进行解耦,下面举个例子来说明:

public class Foo
{
private Bar _bar;
public Foo()
{
_bar
= new Bar();
}
}

  在Foo类中引用了Bar这个类,并且建立了Bar类的实例,这样的话,两个类之间是互相依赖形成紧耦合了,因此可以用如下的代码进行改善,如下:

public class Foo
{
private IBar _bar;
public Foo(IBar bar)
{
_bar
= bar;
}
}

  这样的话,Foo类就不会跟Bar类形成紧密的耦合了,只是依赖于IBar类的接口而已,这样对系统的架构十分有利。下面我们安装Nineject,在visual studio中运行包管理器,输入install-package Nineject.mvc3即可。下面我们来编写相关的接口。

  先实现的是IReviewRepository接口,代码如下:

public interface IReviewRepository
{
    Review
Get(int id);
    IQueryable
<Review> GetAll();
    Review Add(Review review);
    Review Update(Review review);
    void Delete(
int reviewId);
    IEnumerable
<Review> GetByCategory(Category category);
    IEnumerable
<Comment> GetReviewComments(int id);
}

  该接口中提供了基本的crud的方法声明,其实现类代码如下:

public class ReviewRepository : IReviewRepository
{
    
private ReviewedContext _db { get; set; }

    
public ReviewRepository()
        :this (
new ReviewedContext())
    {
        
    }

    
public ReviewRepository(ReviewedContext db)
    {
        _db
= db;
    }

    
public Review Get(int id)
    {
        return _db.Reviews.SingleOrDefault(r
=> r.Id == id);
    }

    
public IQueryable<Review> GetAll()
    {
        return _db.Reviews;
    }

    
public Review Add(Review review)
    {
        _db.Reviews.Add(review);
        _db.SaveChanges();
        return review;
    }

    
public Review Update(Review review)
    {
        _db.Entry(review).State
= EntityState.Modified;
        _db.SaveChanges();
        return review;
    }

    
public void Delete(int reviewId)
    {
        var review
= Get(reviewId);
        _db.Reviews.Remove(review);
    }

    
public IEnumerable<Review> GetByCategory(Category category)
    {
        return _db.Reviews.Where(r
=> r.CategoryId == category.Id);
    }

    
public IEnumerable<Comment> GetReviewComments(int id)
    {
        return _db.Comments.Where(c
=> c.ReviewId == id);
    }
}

  在上面的代码中,ReviewdContext对象以类变量的方式保存,这样会使得通过LINQ访问数据库的时候相当方便。

  而WebAPI有一个相当优秀的特性,那就是能很容易地将DI依赖注入的框架融合起来,这个已经超出本文的讨论翻译,建议读者参考以下的这篇文章(http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/ )。

  在App_Start目录中,包含了一个重要文件叫NinjectCommonWeb.cs(这在安装Ninject的时候会自动把文件添加到App_Start中)。这个文件包含了一个静态类叫NinjectWebCommon,并且有一个方法叫RegisterServices()。在这个方法中,增加如下的代码:

kernel.Bind<IReviewRepository>().To<ReviewRepository>();
kernel.Bind
<ICategoriesRepository>().To<CategoriesRepository>();
kernel.Bind
<ICommentsRepository>().To<CommentsRepository>();
GlobalConfiguration.Configuration.DependencyResolver
= new NinjectResolver(kernel);

  在前面三行代码中,将三个不同的接口和具体的接口的实现类绑定起来了,而第四行代码为webapi设置了相关的依赖注入,详细关于nineject的用法请参考(http://www.strathweb.com/2012/05/using-ninject-with-the-latest-asp-net-web-api-source/ )

0
相关文章