3

asp.net mvc Webアプリケーション内に次のビューがあります。テーブル内にモデルデータを表示するだけで、テーブルの列の先頭に3つのチェックボックスがあり、どの列を抽出して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; }

    }
}

そして、folloiwngモデルクラス:-

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"; }
        }
    }

}

およびfolloiwngモデルクラス:-

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"; }
        }
    }
}

そして最後に、folloiwngモデルクラス:-

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つのアクションを持つコントローラーを作成できます。1つはビューにレコードをレンダリングし、もう1つはレコードをエクスポートします。

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));
            }
        }
    }
}

そして、2つの実装を持つことができます:

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 に答える