PlanetWilson
PlanetWilson

Reputation: 361

Accessing encoded stream in OpenRasta

I have a need to access the encoded stream in OpenRasta before it gets sent to the client. I have tried using a PipelineContributor and registering it before KnownStages.IEnd, tried after KnownStages.IOperationExecution and after KnownStages.AfterResponseConding but in all instances the context.Response.Entity stream is null or empty.

Anyone know how I can do this?

Also I want to find out the requested codec fairly early on yet when I register after KnowStages.ICodecRequestSelection it returns null. I just get the feeling I am missing something about these pipeline contributors.

Upvotes: 1

Views: 142

Answers (1)

Asbjørn Ulsberg
Asbjørn Ulsberg

Reputation: 8820

Without writing your own Codec (which, by the way, is really easy), I'm unaware of a way to get the actual stream of bytes sent to the browser. The way I'm doing this is serializing the ICommunicationContext.Response.Entity before the IResponseCoding known stage. Pseudo code:

class ResponseLogger : IPipelineContributor
{
    public void Initialize(IPipeline pipelineRunner)
    {            
        pipelineRunner
            .Notify(LogResponse)
            .Before<KnownStages.IResponseCoding>();
    }

    PipelineContinuation LogResponse(ICommunicationContext context)
    {
        string content = Serialize(context.Response.Entity);

    }

    string Serialize(IHttpEntity entity)
    {
        if ((entity == null) || (entity.Instance == null))
            return String.Empty;

        try
        {
            using (var writer = new StringWriter())
            {
                using (var xmlWriter = XmlWriter.Create(writer))
                {
                    Type entityType = entity.Instance.GetType();
                    XmlSerializer serializer = new XmlSerializer(entityType);
                    serializer.Serialize(xmlWriter, entity.Instance);
                }

                return writer.ToString();
            }
        }
        catch (Exception exception)
        {
            return exception.ToString();
        }
    }
}

This ResponseLogger is registered the usual way:

ResourceSpace.Uses.PipelineContributor<ResponseLogger>();

As mentioned, this doesn't necessarily give you the exact stream of bytes sent to the browser, but it is close enough for my needs, since the stream of bytes sent to the browser is basically just the same serialized entity.

By writing your own codec, you can with no more than 100 lines of code tap into the IMediaTypeWriter.WriteTo() method, which I would guess is the last line of defense before your bytes are transferred into the cloud. Within it, you basically just do something simple like this:

public void WriteTo(object entity, IHttpEntity response, string[] parameters)
{
    using (var writer = XmlWriter.Create(response.Stream))
    {
        XmlSerializer serializer = new XmlSerializer(entity.GetType());
        serializer.Serialize(writer, entity);
    }
}

If you instead of writing directly to to the IHttpEntity.Stream write to a StringWriter and do ToString() on it, you'll have the serialized entity which you can log and do whatever you want with before writing it to the output stream.

While all of the above example code is based on XML serialization and deserialization, the same principle should apply no matter what format your application is using.

Upvotes: 1

Related Questions