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 ?

1

2 Answers 2

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; }
}
Sign up to request clarification or add additional context in comments.

5 Comments

It would be the same result as the following answer, XmlSerializer serializer = new XmlSerializer(typeof(Adoria)) would occured an error.
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: msdn.microsoft.com/en-us/library/ms733901(v=vs.110).aspx, msdn.microsoft.com/en-us/library/…
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.
Attach a debugger, and put a breakpoint after the serializer.Serialize or serializer.WriteObject (try both alternatives), do you have XML in the builder?
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.
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;
        }
    }
}

2 Comments

I try this, but i get an InvalidOperationException into new XmlSerializer(typeof(Adoria)). An error occurred during the reflection type
Did you try adding [Serializable] attribute to your Adoria class?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.