Skip to content

Instantly share code, notes, and snippets.

@Swimburger
Created November 18, 2022 17:08
Show Gist options
  • Save Swimburger/5202b25936e5ebf5ca0f3d855b9fbb5e to your computer and use it in GitHub Desktop.
Save Swimburger/5202b25936e5ebf5ca0f3d855b9fbb5e to your computer and use it in GitHub Desktop.
Fixing breaking changes in the TwiMLResult class for Twilio.AspNet v7 release

Fixing breaking changes in the TwiMLResult class for Twilio.AspNet v7 release

The v7 release removed the string and XDocument overload for the TwiMLResult constructor. One solution to this is to stop using string and XDocument and replace the code using the MessagingResponse and VoiceResponse classes, so you can keep using TwiMLResult. However, if you want to keep using string and XDocument, I'll share some before and after code for string and XDocument for both ASP.NET Core MVC and ASP.NET MVC on .NET Framework.

ASP.NET Core MVC

Before v7 using string:

using Twilio.AspNet.Core;

public class SmsController : TwilioController
{
    public IActionResult Index()
    {
        return TwiML("<Response><Message>Ahoy!</Message></Response>");
    }
}

After v7 using string:

using Microsoft.AspNetCore.Mvc;

public class SmsController : Controller
{
    public IActionResult Index()
    {
        return Content("<Response><Message>Ahoy!</Message></Response>", "application/xml");
    }
}

Note This is not 100% the same output, as the TwiMLResult would also add the XML declaration: <?xml version="1.0" encoding="utf-8"?>. However, Twilio does not require this, so this is fine.

Before v7 using XDocument:

using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;
using Twilio.AspNet.Core;

public class SmsController : TwilioController
{
    public IActionResult Index()
    {
        XDocument doc = CreateTwiml();

        return TwiML(doc);
    }

    private XDocument CreateTwiml() => XDocument.Parse("<Response><Message>Ahoy!</Message></Response>");
}

After v7 using XDocument:

using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;

public class SmsController : Controller
{
    public async Task Index(CancellationToken cancellationToken)
    {
        XDocument doc = CreateTwiml();
        
        Response.ContentType = "application/xml";
        await doc.SaveAsync(Response.Body, SaveOptions.None, cancellationToken);
    }

    private XDocument CreateTwiml() => XDocument.Parse("<Response><Message>Ahoy!</Message></Response>");
}

To make this more reusable, you can wrap this logic into an action result:

public class XDocumentResult : IActionResult
{
    private readonly XDocument document;

    public XDocumentResult(XDocument document)
    {
        this.document = document;
    }
    
    public async Task ExecuteResultAsync(ActionContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = "application/xml";
        await document.SaveAsync(response.Body, SaveOptions.None, context.HttpContext.RequestAborted);
    }
}

Then you can use the XDocumentResult in your controller:

using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;

public class SmsController : Controller
{
    public IActionResult Index()
    {
        XDocument doc = CreateTwiml();
        
        Response.ContentType = "application/xml";
        return new XDocumentResult(doc);
    }

    private XDocument CreateTwiml() => XDocument.Parse("<Response><Message>Ahoy!</Message></Response>");
}

ASP.NET MVC on .NET Framework

Before v7 using string:

using System.Web.Mvc;
using Twilio.AspNet.Mvc;

public class SmsController : TwilioController
{
    public ActionResult Index()
    {
        return TwiML("<Response><Message>Ahoy!</Message></Response>");
    }
}

After v7 using string:

using System.Web.Mvc;

public class SmsController : Controller
{
    public ActionResult Index()
    {
        return Content("<Response><Message>Ahoy!</Message></Response>", "application/xml");
    }
}

Note This is not 100% the same output, as the TwiMLResult would also add the XML declaration: <?xml version="1.0" encoding="utf-8"?>. However, Twilio does not require this, so this is fine.

Before v7 using XDocument:

using System.Web.Mvc;
using System.Xml.Linq;
using Twilio.AspNet.Mvc;

public class SmsController : TwilioController
{
    public ActionResult Index()
    {
        XDocument doc = CreateTwiml();
        
        return TwiML(doc);
    }

    private XDocument CreateTwiml() => XDocument.Parse("<Response><Message>Ahoy!</Message></Response>");
}

After v7 using XDocument:

using System.Web.Mvc;
using System.Xml.Linq;

public class SmsController : Controller
{
    public void Index()
    {
        XDocument doc = CreateTwiml();
        
        Response.ContentType = "application/xml";
        doc.Save(Response.OutputStream);
    }

    private XDocument CreateTwiml() => XDocument.Parse("<Response><Message>Ahoy!</Message></Response>");
}

To make this more reusable, you can put this logic into an action result:

using System.Web.Mvc;
using System.Xml.Linq;

public class SmsController : Controller
{
    public ActionResult Index()
    {
        XDocument doc = CreateTwiml();

        return new XDocumentResult(doc);
    }

    private XDocument CreateTwiml() => XDocument.Parse("<Response><Message>Ahoy!</Message></Response>");
}

public class XDocumentResult : ActionResult
{
    private readonly XDocument document;

    public XDocumentResult(XDocument document)
    {
        this.document = document;
    }
    
    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.ContentType = "application/xml";
        document.Save(response.OutputStream);
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment