3

我在我的 asp.net mvc web 应用程序中有以下视图:它只是在表格中显示模型数据,表格中有三个复选框,用于选择应将哪些列提取到 excel (.xls) 或文本(.csv) 文件。观点是:-

@model MvcApplication4.Models.SelectedCustomers

@{
    ViewBag.Title = "CustomerDetials";
}
<h3>Select Customers Detials</h3>
<table>
    <tr>
        <th>
            NAME @Html.CheckBox("Name",true)
        </th>
        <th>
            Description @Html.CheckBox("Description",true)
        </th>
        <th>
            Address @Html.CheckBox("Address",true)
        </th>
    </tr>
@foreach (var item in Model.Info) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.description)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.address)
        </td>
    </tr>
}

</table>
<p>
@Html.ActionLink("Back","customer","Home") |
<a href="">extract to excel</a> |
<a href="">extract to text file</a>
</p>

但是任何人都可以就我如何完成以下工作提供一些帮助:-

  1. 开发一个操作方法,当用户单击“提取到 excel”链接时,将返回并打开一个包含 SelectedCustomer 模型对象的 excel 工作表。

  2. 开发一个操作方法,当用户单击“提取到文本文件”链接时,该方法将返回并打开一个包含 SelectedCustomer 模型对象的 .csv 文件。

  3. 我怎样才能只提取其复选框“选中”的列。

谢谢和最好的问候

:::更新:::

我已将我的观点更新为以下内容:-

@model MvcApplication4.Models.SelectedCustomers

@{
    ViewBag.Title = "CustomerDetials";
}

<h3>Select Customers Detials</h3>

@using (Html.BeginForm("Export", null))
{

<table>
        <tr>
            <th>
                NAME @Html.CheckBox("IncludeName",true)
            </th>
            <th>
                Description @Html.CheckBox("IncludeDescription",true)
            </th>
            <th>
                Address @Html.CheckBox("IncludeAddress",true)
            </th>
        </tr>

@foreach (var item in Model.Info) {
    <tr>

       <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.description)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.address)
            </td>
    </tr>
}

</table>
<p>
@Html.ActionLink("Back","customer","Home") |
        <button type="submit" name="format" value="xls">extract to excel</button> |
        <button type="submit" name="format" value="csv">extract to text file</button>
    </p>}

然后添加了以下操作方法:-

[HttpPost]
        public ActionResult Export(ExportViewModel exportOptions,IEnumerable<Account> sc)
        {
          //  var accounts = GetAccounts();
            if (exportOptions.Format == "csv")
            {
                return sc.AsCsvResult(exportOptions);
            }
            else if (exportOptions.Format == "xls")
            {
                return sc.AsXlsResult(exportOptions);
            }

            throw new NotSupportedException(
                string.Format("Unsupported format: {0}", exportOptions.Format)
            );
        }

以及以下模型类:-

public abstract class ExportAccountsResult : ActionResult
{
    protected ExportAccountsResult(IEnumerable<Account> accounts, ExportViewModel exportOptions)
    {

        this.Accounts = accounts;
        this.ExportOptions = exportOptions;
    }

    protected IEnumerable<Account> Accounts { get; private set; }
    protected ExportViewModel ExportOptions { get; private set; }

    protected abstract string ContentType { get; }
    protected abstract string Filename { get; }

    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        var cd = new ContentDisposition
        {
            FileName = this.Filename,
            Inline = false
        };
        response.AddHeader("Content-Disposition", cd.ToString());

        // TODO: Use a real CSV parser here such as https://github.com/JoshClose/CsvHelper/wiki/Basics
        // and never roll your own parser as shown in this oversimplified
        // example. Here's why: http://secretgeek.net/csv_trouble.asp
        using (var writer = new StreamWriter(response.OutputStream))
        {
            foreach (var account in this.Accounts)
            {
               var values = new List<object>();
            if (this.ExportOptions.IncludeName)
            {
                values.Add(account.Name);
            }
            if (this.ExportOptions.IncludeDescription)
            {
                values.Add(account.Description);
            }
            if (this.ExportOptions.IncludeAddress)
            {
                values.Add(account.Address);
            }
            writer.WriteLine(string.Join(", ", values));
            }
        }
    }
}
}

和以下模型类:-

namespace MvcApplication4.Models
{
    public class ExportViewModel
    {
        public string Format { get; set; }
        public bool IncludeName { get; set; }
        public bool IncludeDescription { get; set; }
        public bool IncludeAddress { get; set; }

    }
}

以及以下模型类:-

namespace MvcApplication4.Models
{
    public class CsvResult : ExportAccountsResult
    {
        public CsvResult(IEnumerable<Account> accounts, ExportViewModel exportOptions)
            : base(accounts, exportOptions)
        {
        }

        protected override string ContentType
        {
            get { return "text/csv"; }
        }

        protected override string Filename
        {
            get { return "accounts.csv"; }
        }
    }

}

和以下模型类:-

namespace MvcApplication4.Models
{
    public class XlsResult : ExportAccountsResult
    {
        public XlsResult(IEnumerable<Account> accounts, ExportViewModel exportOptions)
            : base(accounts, exportOptions)
        {
        }

        protected override string ContentType
        {
            get { return "application/vnd.ms-excel"; }
        }

        protected override string Filename
        {
            get { return "accounts.csv"; }
        }
    }
}

最后是以下模型类:-

namespace MvcApplication4.Models
{
    public class SelectedCustomers
    {
        public IEnumerable<Account> Info { get; set; }
    }
    public static class ActionResultextensions
    {
        public static ActionResult AsCsvResult(this IEnumerable<Account> accounts, ExportViewModel exportOptions)
        {
            return new CsvResult(accounts, exportOptions);
        }

        public static ActionResult AsXlsResult(this IEnumerable<Account> accounts, ExportViewModel exportOptions)
        {
            return new XlsResult(accounts, exportOptions);
        }
    }
}

但是当我运行应用程序时,我得到了以下异常:-

System.NullReferenceException was unhandled by user code
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=MvcApplication4
  StackTrace:
       at MvcApplication4.Models.ExportAccountsResult.ExecuteResult(ControllerContext context) in c:\Users\Administrator\Documents\Visual Studio 2012\Projects\MvcApplication4\MvcApplication4\Models\ExportAccountResult.cs:line 43
       at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
       at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19()
       at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
  InnerException: 

在 ExportAccountResult.cs 中的这段代码上:-

foreach (var account in this.Accounts)

那么可能出了什么问题?BR

4

1 回答 1

1

您可以将记录放入表单并制作 2 个链接提交按钮。让我们举个例子。我们将对文本文件和 Excel 文件格式都使用 CSV,因为 Excel 可以理解 CSV。如果您需要为 Excel 导出应用一些特殊格式,您可以使用第三方库,例如OpenXML

让我们从定义我们的视图模型开始:

public class SelectedCustomers
{
    public IEnumerable<Account> Info { get; set; }
}

public class Account
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string Address { get; set; }
}

public class ExportViewModel
{
    public string Format { get; set; }
    public bool IncludeName { get; set; }
    public bool IncludeDescription { get; set; }
    public bool IncludeAddress { get; set; }
}

那么我们可以有一个具有 2 个操作的控制器 - 一个在视图上呈现记录,一个用于导出它们:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new SelectedCustomers
        {
            Info = GetAccounts()
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Export(ExportViewModel exportOptions)
    {
        var accounts = GetAccounts();
        if (exportOptions.Format == "csv")
        {
            return accounts.AsCsvResult(exportOptions);
        }
        else if (exportOptions.Format == "xls")
        {
            return accounts.AsXlsResult(exportOptions);
        }

        throw new NotSupportedException(
            string.Format("Unsupported format: {0}", exportOptions.Format)    
        );
    }

    private static IEnumerable<Account> GetAccounts()
    {
        // TODO: those records will probably come from a database or something
        // I have hardcoded them here to make my answer more clear
        // and not dependent on some data stores
        return Enumerable.Range(1, 5).Select(x => new Account
        {
            Name = "name " + x,
            Description = "description " + x,
            Address = "address " + x
        });
    }
}

然后我们定义对应的视图:

@model SelectedCustomers

<h3>Select Customers Detials</h3>

@using (Html.BeginForm("Export", null))
{
    <table>
        <tr>
            <th>
                NAME @Html.CheckBox("IncludeName", true)
            </th>
            <th>
                Description @Html.CheckBox("IncludeDescription", true)
            </th>
            <th>
                Address @Html.CheckBox("IncludeAddress", true)
            </th>
        </tr>
        @foreach (var item in Model.Info) {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Description)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Address)
                </td>
            </tr>
        }
    </table>

    <p>
        @Html.ActionLink("Back","customer","Home") |
        <button type="submit" name="format" value="xls">extract to excel</button> |
        <button type="submit" name="format" value="csv">extract to text file</button>
    </p>
}

接下来我们实现控制器中使用的自定义扩展方法,返回 2 个自定义操作结果:

public static class ActionResultextensions
{
    public static ActionResult AsCsvResult(this IEnumerable<Account> accounts, ExportViewModel exportOptions)
    {
        return new CsvResult(accounts, exportOptions);
    }

    public static ActionResult AsXlsResult(this IEnumerable<Account> accounts, ExportViewModel exportOptions)
    {
        return new XlsResult(accounts, exportOptions);
    }
}

最后一部分当然是定义CsvResultXlsResult自定义操作结果。由于我们将在这两种情况下使用 CSV,我们可以有一个基类:

public abstract class ExportAccountsResult : ActionResult
{
    protected ExportAccountsResult(IEnumerable<Account> accounts, ExportViewModel exportOptions)
    {
        this.Accounts = accounts;
        this.ExportOptions = exportOptions;
    }

    protected IEnumerable<Account> Accounts { get; private set; }
    protected ExportViewModel ExportOptions { get; private set; }

    protected abstract string ContentType { get; }
    protected abstract string Filename { get; }

    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        var cd = new ContentDisposition
        {
            FileName = this.Filename,
            Inline = false
        };
        response.AddHeader("Content-Disposition", cd.ToString());

        // TODO: Use a real CSV parser here such as https://github.com/JoshClose/CsvHelper/wiki/Basics
        // and never roll your own parser as shown in this oversimplified
        // example. Here's why: http://secretgeek.net/csv_trouble.asp
        using (var writer = new StreamWriter(response.OutputStream))
        {
            foreach (var account in this.Accounts)
            {
                var values = new List<object>();
                if (this.ExportOptions.IncludeName)
                {
                    values.Add(account.Name);
                }
                if (this.ExportOptions.IncludeDescription)
                {
                    values.Add(account.Description);
                }
                if (this.ExportOptions.IncludeAddress)
                {
                    values.Add(account.Address);
                }
                writer.WriteLine(string.Join(", ", values));
            }
        }
    }
}

然后我们可以有两个实现:

public class CsvResult : ExportAccountsResult
{
    public CsvResult(IEnumerable<Account> accounts, ExportViewModel exportOptions)
        : base(accounts, exportOptions)
    {
    }

    protected override string ContentType
    {
        get { return "text/csv"; }
    }

    protected override string Filename
    {
        get { return "accounts.csv"; }
    }
}

public class XlsResult : ExportAccountsResult
{
    public XlsResult(IEnumerable<Account> accounts, ExportViewModel exportOptions)
        : base(accounts, exportOptions)
    {
    }

    protected override string ContentType
    {
        get { return "application/vnd.ms-excel"; }
    }

    protected override string Filename
    {
        get { return "accounts.csv"; }
    }
}
于 2012-12-24T10:37:06.040 回答