C# ASP.Net标识、简洁和;存储过程最佳实践

C# ASP.Net标识、简洁和;存储过程最佳实践,c#,asp.net,stored-procedures,asp.net-identity,dapper,C#,Asp.net,Stored Procedures,Asp.net Identity,Dapper,我目前正在跟随这篇文章学习Dapper micro ORM和ASP.NET identity。我想通过实现一个通用的存储库模式来混合它,它将帮助我完成基本的CRUD操作 以下是我的课程: User.cs public class User : IUser { public Guid UserId { get; set; } public string UserName { get; set; } public string PasswordHash { get; set;

我目前正在跟随这篇文章学习Dapper micro ORM和ASP.NET identity。我想通过实现一个通用的存储库模式来混合它,它将帮助我完成基本的CRUD操作

以下是我的课程:

User.cs

public class User : IUser
{
    public Guid UserId { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }

    string IUser<string>.Id
    {
        get { return UserId.ToString(); }
    }
}
public class Repository<T> : IRepository<T> where T : class
{
    public int ExecuteScalar(string query, object arguments)
    {
        var id = 0;

        using (var connection = ConnectionFactory.CreateConnection())
        {
            id = connection.ExecuteScalar<int>(query, arguments, commandType: CommandType.StoredProcedure);
        }

        return id;
    }
}
public class UserStore : IUserStore<User>, IUserLoginStore<User>, IUserPasswordStore<User>, IUserSecurityStampStore<User>
{
    private IRepository<User> repository;

    public UserStore(IRepository<User> repository)
    {
        this.repository = repository;
    }

    #region IUserStore
    public virtual Task CreateAsync(User user)
    {
        if (user == null)
            throw new ArgumentNullException("user");

        return Task.Factory.StartNew(() =>
        {
            user.UserId = Guid.NewGuid();
            repository.ExecuteScalar("sp_InsertUser",
                new { UserId = user.UserId, UserName = user.UserName, Password = user.PasswordHash,
                    SecurityStamp = user.SecurityStamp });
        });
    }
}
公共类用户:IUser
{
公共Guid用户标识{get;set;}
公共字符串用户名{get;set;}
公共字符串密码哈希{get;set;}
公共字符串SecurityStamp{get;set;}
字符串IUser.Id
{
获取{return UserId.ToString();}
}
}
Repository.cs

public class User : IUser
{
    public Guid UserId { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }

    string IUser<string>.Id
    {
        get { return UserId.ToString(); }
    }
}
public class Repository<T> : IRepository<T> where T : class
{
    public int ExecuteScalar(string query, object arguments)
    {
        var id = 0;

        using (var connection = ConnectionFactory.CreateConnection())
        {
            id = connection.ExecuteScalar<int>(query, arguments, commandType: CommandType.StoredProcedure);
        }

        return id;
    }
}
public class UserStore : IUserStore<User>, IUserLoginStore<User>, IUserPasswordStore<User>, IUserSecurityStampStore<User>
{
    private IRepository<User> repository;

    public UserStore(IRepository<User> repository)
    {
        this.repository = repository;
    }

    #region IUserStore
    public virtual Task CreateAsync(User user)
    {
        if (user == null)
            throw new ArgumentNullException("user");

        return Task.Factory.StartNew(() =>
        {
            user.UserId = Guid.NewGuid();
            repository.ExecuteScalar("sp_InsertUser",
                new { UserId = user.UserId, UserName = user.UserName, Password = user.PasswordHash,
                    SecurityStamp = user.SecurityStamp });
        });
    }
}
公共类存储库:IRepository,其中T:class
{
public int ExecuteScalar(字符串查询、对象参数)
{
var-id=0;
使用(var connection=ConnectionFactory.CreateConnection())
{
id=connection.ExecuteScalar(查询、参数、commandType:commandType.StoredProcess);
}
返回id;
}
}
UserStore.cs

public class User : IUser
{
    public Guid UserId { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }

    string IUser<string>.Id
    {
        get { return UserId.ToString(); }
    }
}
public class Repository<T> : IRepository<T> where T : class
{
    public int ExecuteScalar(string query, object arguments)
    {
        var id = 0;

        using (var connection = ConnectionFactory.CreateConnection())
        {
            id = connection.ExecuteScalar<int>(query, arguments, commandType: CommandType.StoredProcedure);
        }

        return id;
    }
}
public class UserStore : IUserStore<User>, IUserLoginStore<User>, IUserPasswordStore<User>, IUserSecurityStampStore<User>
{
    private IRepository<User> repository;

    public UserStore(IRepository<User> repository)
    {
        this.repository = repository;
    }

    #region IUserStore
    public virtual Task CreateAsync(User user)
    {
        if (user == null)
            throw new ArgumentNullException("user");

        return Task.Factory.StartNew(() =>
        {
            user.UserId = Guid.NewGuid();
            repository.ExecuteScalar("sp_InsertUser",
                new { UserId = user.UserId, UserName = user.UserName, Password = user.PasswordHash,
                    SecurityStamp = user.SecurityStamp });
        });
    }
}
公共类用户存储:IUserStore、IUserLoginStore、IUserPasswordStore、IUserSecurityStampStore
{
私有存储库;
公共用户存储(IRepository存储库)
{
this.repository=存储库;
}
#区域IUserStore
公共虚拟任务CreateAsync(用户)
{
if(user==null)
抛出新的ArgumentNullException(“用户”);
返回Task.Factory.StartNew(()=>
{
user.UserId=Guid.NewGuid();
repository.ExecuteScalar(“sp_InsertUser”,
新的{UserId=user.UserId,UserName=user.UserName,Password=user.PasswordHash,
SecurityStamp=user.SecurityStamp});
});
}
}
我提供其他方法和类并不是为了缩短我的文章:将创建SQL连接的连接工厂,也是
UserStore
中接口的方法部分

我有以下问题:

  • 是否有办法将
    User
    对象原样传递给
    ExecuteScalar
    方法?而不是每次都输入所有参数
  • 将CRUD操作创建为存储过程真的是最佳实践吗?例如这里的
    sp\u InsertUser
  • 这里的异步方法会导致问题吗
  • 如果我想编写一个SQL查询并将其传递给Dapper(将查询添加到XML文件并从中读取)。我也看到了这一点,我喜欢所有的东西都是通用的,我可以最小化我的代码并创建一些整洁的东西。调用字符串格式并传递参数是最佳做法吗

    格式(“更新[{0}] 集合{1},其中{2},typeof(T).Name,sqlValuePairs,sqlIdPairs)

  • 我真的为这篇长篇大论道歉,但我对这一点真的很陌生,我正在努力学习这些技术。但是我越是搜索文章,我就越感到困惑

  • 如果参数名和属性名完全匹配,则只需传递
    user
    ;但是,请注意,虽然dapper可以尝试检查内联文本需要哪些参数,但它无法对存储过程执行此操作,因此它会尝试发送所有内容
  • 主要是意见和偏好;有像dapper.contrib和dapperextensions这样的工具可以自动执行此操作
  • 您应该更喜欢像ExecuteScalarAsync这样的实际异步方法
  • 似乎是一个陈述,而不是一个问题
  • 对于已编辑的第4部分:

  • 好吧,有很多方法可以导致脆弱性;但如果你严格控制输入,它可能会工作;有时候我也做过类似的事情;但请注意,这正是像“dapper.contrib”这样的东西带来的

  • @马克:谢谢你在dapper.contrib中的贡献!正如你所说,这正是你想要的!1-由于dapper.contrib不提供此功能,因此使用dapper调用存储过程是否合适?2-我有一个带有外键约束的表。插入带有dapper.contrib的记录是否会导致问题(没有属性)?再次感谢你@NicolasJamal实际上,除了构建/部署它之外,我还没有接触过“contrib”;它不是我常规工具的一部分,但它的存在很好