1

I try to use web api to return a list of items.

This is my Controller :

public class RecipesController : ApiController
{
    /// <summary>
    /// Model to get recipes datas
    /// </summary>
    private readonly RecipeModel _recipeModel = new RecipeModel();

    /// <summary>
    /// Gets the recipe by division identifier.
    /// </summary>
    /// <param name="id">The div identifier.</param>
    [ActionName("Division")]
    public Adoria GetRecipeByDivisionId(int id)
    {
        return _recipeModel.GetRecipeByDivisionId(id);
    }
}

For the moment, this is called by an ASP page using JavaScript :

function RedirectToReport(){
var url = $("#valSelectedCheckBox").val(); // url of my web api method
location.href = url;
}

It displays the xml file on the browser.

I don't want to display it on the browser but download it.

Do you have an idea of the purpose ?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
blasil64
  • 33
  • 1
  • 8

2 Answers2

1

Create this ActionResult (so it's reusable from elsewhere in your app). I took a starting point from http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/ActionResults/ActionResults/Results/OkFileDownloadResult.cs, this site has many more useful examples.

public class OkXmlDownloadResult : IHttpActionResult
{
    private readonly ApiController _controller;

    public OkXmlDownloadResult(string xml, string downloadFileName,
        ApiController controller)
    {
        if (xml == null)
        {
            throw new ArgumentNullException("xml");
        }

        if (downloadFileName == null)
        {
            throw new ArgumentNullException("downloadFileName");
        }

        if (controller == null)
        {
            throw new ArgumentNullException("controller");
        }

        Xml = xml;
        ContentType = "application/xml";
        DownloadFileName = downloadFileName;
        _controller = controller;
    }

    public string Xml { get; private set; }

    public string ContentType { get; private set; }

    public string DownloadFileName { get; private set; }

    public HttpRequestMessage Request
    {
        get { return _controller.Request; }
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(Execute());
    }

    private HttpResponseMessage Execute()
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StringContent(Xml);
        response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(ContentType);
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = DownloadFileName
        };
        return response;
    }
}

Then use it in your controller (I added a simple way to get the XML, it's up to you how to get generate it):

public class ValuesController : ApiController
{
    public IHttpActionResult Get()
    {
        User user = new User()
        {
            FirstName = "First",
            LastName = "Last"
        };

        // Alternative 1
        XmlSerializer serializer = new XmlSerializer(typeof(User));

        // Alternative 2
        // DataContractSerializer serializer = new DataContractSerializer(typeof(User));

        StringBuilder builder = new StringBuilder();
        using (StringWriter writer = new StringWriter(builder))
        {
            serializer.Serialize(writer, user);

            // alternative 2
            // serializer.WriteObject(writer, user);
        }

        // create XML from your data.
        return new OkXmlDownloadResult(builder.ToString(), "myfile.xml", this);
    }
}

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
Yishai Galatzer
  • 8,791
  • 2
  • 32
  • 41
  • It would be the same result as the following answer, XmlSerializer serializer = new XmlSerializer(typeof(Adoria)) would occured an error. – blasil64 May 06 '14 at 06:30
  • Added a sample on how to use DataContractSerializer (typically more lenient than XmlSerializer). If that doesn't work you will need to read on how to make your types ready to be serialized. Here are a couple of links: http://msdn.microsoft.com/en-us/library/ms733901(v=vs.110).aspx, http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer(v=vs.110).aspx – Yishai Galatzer May 06 '14 at 15:06
  • IEnumerable<> was not serializable. Replace by List<>. But nothing is dowloadind, fiddler send the response : [Fiddler] ReadResponse() failed: The server did not return a response for this request. Server returned 0 bytes. – blasil64 May 07 '14 at 08:00
  • Attach a debugger, and put a breakpoint after the serializer.Serialize or serializer.WriteObject (try both alternatives), do you have XML in the builder? – Yishai Galatzer May 07 '14 at 08:07
  • Workks fine finally. I use var builder = new StringBuilder(); and result.Content = new StringContent(builder.ToString());. It generates the xml file to the screen and with result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("export_{0}.xml", id) }; the xml file is downloading. Thanks. – blasil64 May 07 '14 at 08:26
0

Try the following code

public class RecipesController : ApiController
{
    private readonly RecipeModel _recipeModel = new RecipeModel();

    [ActionName("Division")]
    public HttpResponseMessage GetRecipeByDivisionId(int id)
    {
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);

        var adoria = _recipeModel.GetRecipeByDivisionId(id);

        XmlSerializer serializer = new XmlSerializer(typeof(Adoria));
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream))
            {
                serializer.Serialize(xmlWriter, adoria);
            }

            result.Content = new StreamContent(memoryStream);
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

            return result;
        }
    }
}
Volkan Vardar
  • 314
  • 3
  • 8