简体   繁体   中英

How to setup web api controller for ZipFile

I am trying to create and return a zip file with selected documents. The console shows that the selected DocumentId's are being sent from the Angular controller to the api but I am getting a null error.

ApiController

 public HttpResponseMessage Get(string[] id)
    {
        List<Document> documents = new List<Document>();
        using (var context = new ApplicationDbContext())
        {
            Document document = context.Documents.Find(id);

            if (document == null)
            {
                if (document == null)
                {
                    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
                }
            }

            using (var zipFile = new ZipFile())
            {
                // Make zip file
                foreach (var d in documents)
                {
                    var dt = d.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-');
                    string fileName = String.Format("{0}-{1}-{2}.pdf", dt, d.PipeName, d.LocationAb);
                    zipFile.AddEntry(fileName, d.DocumentUrl);
                }

                return ZipContentResult(zipFile);
            }
        }
    }

    protected HttpResponseMessage ZipContentResult(ZipFile zipFile)
    {

        var pushStreamContent = new PushStreamContent((stream, content, context) =>
        {
            zipFile.Save(stream);
            stream.Close(); // After save we close the stream to signal that we are done writing.
        }, "application/zip");

        return new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };
    }

UPDATE

public HttpResponseMessage Get([FromUri] string[] id)
    {
        var documents = new List<Document>();
        using (var context = new ApplicationDbContext())
        {
            foreach (string doc in id)
            {
                Document document = context.Documents.Find(new object[] { doc });
                if (document == null)
                {
                    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
                }

                documents.Add(document);
            }

            using (var zipFile = new ZipFile())
            {
                // Make zip file
                foreach (var d in documents)
                {
                    var dt = d.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-');
                    string fileName = String.Format("{0}-{1}-{2}.pdf", dt, d.PipeName, d.LocationAb);
                    zipFile.AddEntry(fileName, d.DocumentUrl);
                }

                return ZipContentResult(zipFile);
            }
        }
    }

ERROR

{"The argument types 'Edm.Int32' and 'Edm.String' are incompatible for this operation. Near WHERE predicate, line 1, column 82."}

STACKTRACE

 at System.Data.Entity.Internal.Linq.InternalSet`1.FindInStore(WrappedEntityKey key, String keyValuesParamName)
   at System.Data.Entity.Internal.Linq.InternalSet`1.Find(Object[] keyValues)
   at System.Data.Entity.DbSet`1.Find(Object[] keyValues)
   at  TransparentEnergy.ControllersAPI.apiZipPipeLineController.Get(String[] id)  in e:\Development\TransparentEnergy\TransparentEnergy\ControllersAPI  \BatchZipApi\apiZipPipeLineController.cs:line 25
   at lambda_method(Closure , Object , Object[] )
   at  System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor. <>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[]  methodParameters)
   at  System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Exec       ute(Object instance, Object[] arguments)
   at  System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpCo       ntrollerContext controllerContext, IDictionary`2 arguments,  CancellationToken cancellationToken)

观看截图

New Screenshot of watch after changing string[] id to List id 新截图

Unless you forgot to copy all the code into the question you never add anything to the documents list object.

At the start you create a new List object named documents:

List<Document> documents = new List<Document>();

You then search for items and place them in a new document object:

Document document = context.Documents.Find(id);

Then when attempting to make the zip file you are accessing the first created List object that has nothing put into it.

foreach (var d in documents)

I believe this is then causing your save of the zip file to throw an exception

zipFile.Save(stream);

In the find line above

 Document document = context.Documents.Find(id); 

did you intend

 documents = context.Documents.Find(id); 

UPDATE 2

I set up a database with your information, created a MVC web api that takes a POST of JSON to pass the data. This populates the list with items pulled from a database by ID.

[HttpPost]
[ActionName("ZipFileAction")]
public HttpResponseMessage ZipFiles([FromBody]int[] id)
{
    if (id == null)
    {//Required IDs were not provided
        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
    }

    List<Document> documents = new List<Document>();
    using (var context = new ApplicationDbContext())
    {
        foreach (int NextDocument in id)
        {
            Document document = context.Documents.Find(NextDocument);

            if (document == null)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
            }

            documents.Add(document);
        }

        using (var zipFile = new ZipFile())
        {
            // Make zip file
            foreach (var d in documents)
            {
                var dt = d.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-');
                string fileName = String.Format("{0}-{1}-{2}.pdf", dt, d.PipeName, d.LocationAb);
                zipFile.AddEntry(fileName, d.DocumentUrl);
            }

            return ZipContentResult(zipFile);
        }
    }
}

{"The argument types 'Edm.Int32' and 'Edm.String' are incompatible ..."}

Sounds like your key column is an int type and you are searching it using a string. Try changing the type of the parameter from string to int. I renamed it ids as it seems to be a list of document identifiers.

An optimized version would get all needed documents in a single query :

public HttpResponseMessage Get([FromUri] int[] ids)
{
    using (var context = new ApplicationDbContext())
    {
        var documents = context.Documents.Where(doc => ids.Contains(doc.Id)).ToList();
        if (documents.Count != ids.Length)
        {
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
        }

        using (var zipFile = new ZipFile())
        {
            // Make zip file
            foreach (var d in documents)
            {
                var dt = d.DocumentDate.ToString("y").Replace('/', '-').Replace(':', '-');
                string fileName = String.Format("{0}-{1}-{2}.pdf", dt, d.PipeName, d.LocationAb);
                zipFile.AddEntry(fileName, d.DocumentUrl);
            }

            return ZipContentResult(zipFile);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM