如何避免过度使用ViewBag

时间:2015-03-17 14:21:21

标签: c# asp.net asp.net-mvc

我有这个项目,我正在努力。在索引视图中,我必须显示许多可能不相关的数据。目前我在控制器中的索引动作看起来完全搞砸了,因为我可以说我已经以非常业余的方式完成了它。我已经阅读了很多关于ViewBag的使用情况,有些人甚至说应该避免完全使用它并使用ViewModel代替。我一直在实现ViewModel,我理解它的用处,我很欣赏它。但是在这个项目中,我不知道如何将我的请求转换为一个视图模型,因为我查询的是一些不相关的模型,所以我无法开始使用join语句。见下面的代码

public ActionResult Index()
{

    var db = new ApplicationDbContext();    
    var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
    var CurrentUser = manager.FindById(User.Identity.GetUserId());
  /*******counts of loans*******/
    var PendingCounts = db.Transaction.Where(t => t.Status.Status == "Pending" && t.AgentId == CurrentUser.SalesAgent.AgentId).Count();
    var DeclinedCounts = db.Transaction.Where(t => t.Status.Status == "Declined" && t.AgentId == CurrentUser.SalesAgent.AgentId).Count();
    var ApprovedCounts = db.Transaction.Where(t => t.Status.Status == "Approved" && t.AgentId == CurrentUser.SalesAgent.AgentId).Count();   
    ViewBag.PendingCounts = PendingCounts;
    ViewBag.DeclinedCounts = DeclinedCounts;
    ViewBag.ApprovedCounts = ApprovedCounts;   
    /***Percentage of pending, approved and declined loans in counts******/
    decimal PendingCount = (decimal)PendingCounts;
    decimal DeclinedCount = (decimal)DeclinedCounts;
    decimal ApprovedCount = (decimal)ApprovedCounts;    
    decimal sum = PendingCount + DeclinedCount + ApprovedCount;    
    decimal PendingPercent = (PendingCount / sum) * 100;
    decimal DeclinedPercent = (DeclinedCount / sum) * 100;
    decimal ApprovedPercent = (ApprovedCount / sum) * 100;   
    ViewBag.PendingPercent = PendingPercent;
    ViewBag.DeclinedPercent = DeclinedPercent;
    ViewBag.ApprovedPercent = ApprovedPercent;    
    /****Value of loans******/
    //select SUM(AmountRequested) as totalPending from Transactions where StatusId = 1;     
    var ValuePending = db.Transaction.Where(t => t.AgentId == CurrentUser.SalesAgent.AgentId && t.Status.Status == "Pending").Select(t => (decimal?)t.AmountRequested).Sum() ?? 0;
    var ValueApproved = db.Transaction.Where(t => t.AgentId == CurrentUser.SalesAgent.AgentId && t.Status.Status == "Approved").Select(t => (decimal?)t.AmountApproved).Sum() ?? 0;
    var ValueDeclined = db.Transaction.Where(t => t.AgentId == CurrentUser.SalesAgent.AgentId && t.Status.Status == "Declined").Select(t => (decimal?)t.AmountRequested).Sum() ?? 0;  
    ViewBag.ValuePending = ValuePending;
    ViewBag.ValueApproved = ValueApproved;
    ViewBag.ValueDeclined = ValueDeclined;   
    var thisDate = DateTime.Now;
    var starting = new DateTime(thisDate.Year, thisDate.Month, 1);
    var ending = starting.AddMonths(1);
    var SpecifiedTotal = (from t in db.Transaction
                          where t.AgentId == CurrentUser.SalesAgent.AgentId
                          && t.Status.Status == "Approved"
                          && t.DateApproved >= starting && t.DateApproved < ending
                          select (decimal?)t.AmountApproved).Sum() ?? 0;

    var MonthlyTarget = db.SalesAgent.Where(t => t.AgentId == CurrentUser.SalesAgent.AgentId).Select(t => (decimal)t.MonthlyTarget).FirstOrDefault();
    var today = DateTime.Now;
    var year = DateTime.Now.Year;
    var month = DateTime.Now.Month;
    var day = DateTime.Now.Day;
    var NoOfDays = DateTime.DaysInMonth(year, month);

    var start = today;
    var stop = new DateTime(year, month, NoOfDays);

    int WorkingDaysLeft = GetNumberOfWorkingDays(start, stop);
    decimal RunRate = Math.Round((MonthlyTarget - SpecifiedTotal) / WorkingDaysLeft, 2);
    ViewBag.RunRate = RunRate.ToString("N0");
    /***Get initials of current user*///
    var firstname = db.SalesAgent.Where(s => s.AgentId == CurrentUser.SalesAgent.AgentId).Select(s => s.AgentFirstName.Substring(0, 1)).SingleOrDefault();
    var lastname = db.SalesAgent.Where(s => s.AgentId == CurrentUser.SalesAgent.AgentId).Select(s => s.AgentLastName.Substring(0, 1)).SingleOrDefault();
    //ViewBag.firstnameletter = firstnameletter;
    //ViewBag.lastnameletter = lastnameletter;
    return View();
}

正如您所看到的,我已经将大量数据填充到ViewBag中,因为我需要在我的视图中显示它,例如我的视图看起来像这样

@{
    ViewBag.Title = "Home Page";
}

<div class="imagecircle">
    @ViewBag.firstnameletter @ViewBag.lastnameletter
</div>

<div class="row searchForm">
    <form action="/Home/Index" method="post">

        <div class="col-lg-3">
            <label>Start</label>
            <input type="date" class="StartDate form-control" name="StartDate" />
        </div>
        <div class="col-lg-3">
            <label>End</label>
            <input type="date" class="EndDate form-control" name="EndDate" />
        </div>
        <input type="submit" value="Search" class="submit btn btn-default " />

    </form>
</div>

<div class="row header">
    <div class="col-lg-3 section">
        <div class="row">
            <div class="col-lg-8">
                <h4><span class="countNumber">@ViewBag.PendingCounts</span></h4> Transaction(s) Pending
                <h4> <span class="countNumber">@ViewBag.PendingPercent</span>%</h4> Transaction(s) Pending
                <h4><span class="countNumber">@ViewBag.ValuePending</span></h4> in value so far
            </div>
            <div class="col-lg-4 countHeader">
                <i class="fa fa-spinner fa-spin"></i>
               <h5>Pending</h5> 
            </div>
        </div>
    </div>
    <div class="col-lg-3 section">
        <div class="row">
            <div class="col-lg-8">

                <h4><span class="countNumber">@ViewBag.ApprovedCounts</span></h4> Transaction(s) Approved
                <h4><span class="countNumber">@ViewBag.ApprovedPercent</span>%</h4> Transaction(s) Approved
                <h4><span class="countNumber">@ViewBag.ValueApproved</span></h4> in value so far

            </div>
            <div class="col-lg-4 countHeader">
                <i class="fa fa-check-circle-o"></i>
                <h5>Approved</h5>
            </div>
        </div>
    </div>
    <div class="col-lg-3 section">
        <div class="row">
            <div class="col-lg-8">
                <h4><span class="countNumber">@ViewBag.DeclinedCounts</span></h4> Transaction(s) Declined
                <h4><span class="countNumber">@ViewBag.DeclinedPercent</span>%</h4> Transaction(s) Declined
                <h4><span class="countNumber">@ViewBag.ValueDeclined</span></h4> in value so far
            </div>
            <div class="col-lg-4 countHeader">
                <i class="fa fa-remove"></i>
                <h5>Declined</h5>
            </div>
        </div>
    </div>
</div>



<div class="row">
    <div class="col-lg-12 RunRate">
      <p><sup><i class="fa fa-exclamation-circle"></i></sup>Run Rate = &#8358 @ViewBag.RunRate</p> 
        <p>This is the amount you should get disbursed daily in order to meet your target this month.</p> 
    </div>
</div>

因为我需要对查询结果进行大量计算,所以我发现很难使用ViewModel,因此我坚持使用ViewBag。我知道这远非专业,因为它看起来不干净和光滑。我想我会尝试重构那些我期待单个结果进入方法的单个查询,但您认为我需要对上面的代码做些什么改进?帮助代码示例。

1 个答案:

答案 0 :(得分:1)

ViewModels存储视图所需的表示逻辑。

虽然我质疑为什么许多计算不属于模型本身,但我将其作为重构练习,将业务逻辑从视图模型中移除到模型中。

此外,我将重构视图以使用viewmodel作为读者的练习。

以下是您的资料的视图模型示例:

public class TransactionViewModel
{
    public TransactionViewModel(
        List<Transaction> transactions,
        SalesAgent salesAgent)
    {
        Transactions = transactions;
        SalesAgent = salesAgent;
    }

    public List<Transaction> Transactions { get; set; }

    public SalesAgent SalesAgent { get; set; }

    public decimal MonthlyTarget
    {
        get { return (decimal) SalesAgent.MonthlyTarget; }
    }

    public string SalesAgentInitials
    {
        get
        {
            return
                string.Format(
                    "{0}.{1}.",
                    SalesAgent.FirstName.First(),
                    SalesAgent.LastName.First());
        }
    }

    public IEnumerable<Transaction> ApprovedTransactions
    {
        get { return Transactions.Where(t => t.Status.Status == "Approved"); }
    }

    public IEnumerable<Transaction> PendingTransactions
    {
        get { return Transactions.Where(t => t.Status.Status == "Pending"); }
    }

    public IEnumerable<Transaction> DeclinedTransactions
    {
        get { return Transactions.Where(t => t.Status.Status == "Declined"); }
    }

    public int ApprovedCount
    {
        get { ApprovedTransactions.Count(); }
    }

    public int PendingCount
    {
        get { PendingTransactions.Count(); }
    }

    public int DeclinedCount
    {
        get { DeclinedTransactions.Count(); }
    }

    public int TotalCount
    {
        get { return Transactions.Count; }
    }

    public decimal ApprovedPercent
    {
        get { return (decimal) ApprovedCount / TotalCount }
    }

    public decimal PendingPercent
    {
        get { return (decimal) PendingCount / TotalCount }
    }

    public decimal DeclinedPercent
    {
        get { return (decimal) DeclinedCount / TotalCount }
    }

    public decimal ApprovedValue
    {
        get { return ApprovedTransactions.Select(t => (decimal?)t.AmountRequested).Sum() ?? 0; }
    }

    public decimal PendingValue
    {
        get { return PendingTransactions.Select(t => (decimal?)t.AmountRequested).Sum() ?? 0; }
    }

    public decimal DeclinedValue
    {
        get { return DeclinedTransactions.Select(t => (decimal?)t.AmountRequested).Sum() ?? 0; }
    }

    public DateTime StartMonth
    {
        get { return new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1); }
    }

    public DateTime EndMonth
    {
        get { return StartMonth.AddMonths(1); }
    }

    public int DaysInMonth
    {
        get { return (EndMonth - StartMonth).Days; }
    }

    public int WorkingDaysLeftInMonth
    {
        get
        {
            Enumerable
                .Range(DateTime.Today.Day, DaysInMonth)
                .Select(d => new DateTime(DateTime.Today.Year, DateTime.Today.Month, d))
                .Count(date =>
                    date.DayOfWeek != DayOfWeek.Saturday &&
                    date.DayOfWeek != DayOfWeek.Sunday);
        }
    }

    public decimal SpecifiedTotal
    {
        get
        {
            return
                ApprovedTransactions
                    .Where(t => t.DateApproved >= StartMonth && t.DateApproved < EndMonth)
                    .Select(t => (decimal?) t.AmountApproved)
                    .Sum() ?? 0;
        }
    }

    public decimal RunRate
    {
        get { return Math.Round((MonthlyTarget - SpecifiedTotal) / WorkingDaysLeftInMonth, 2); }
    }

    public string RunRateFormat
    {
        get { return RunRate.ToString("N0"); }
    }
}

这简化了行动:

public ActionResult Index()
{
    var db = new ApplicationDbContext();    
    var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
    var CurrentUser = manager.FindById(User.Identity.GetUserId());

    var loans =
        db.Transaction
          .Where(t =>
              t.AgentId == CurrentUser.SalesAgent.AgentId)
          .ToList();

    var salesAgent = 
        db.SalesAgent
          .FirstOrDefault(s => s.AgentId == CurrentUser.SalesAgent.AgentId);

    var viewModel = new TransactionViewModel(loans, salesAgent)

    return View(viewModel);
}