1

Any given model in my application might implement the IHasOpenGraphMetadata, if that's the case, a call to @Html.Partial("_OpenGraphMetadata") in my layout will render the related metadata, by accessing the model through that interface.

All's good and clean. That is until I wanted to do that from a partial action.

In /Home/Index I have the following call: @Html.Action("List", "Posts")

This returns:

public ActionResult List(long? timestamp = null, int count = 8)
{
    IEnumerable<Post> posts = postService.GetLatest(timestamp, count);
    PostListModel model = mapper.Map<IEnumerable<Post>, PostListModel>(posts);
    return PartialView(model);
}

The issue becomes apparent here: the actual model for /Home/Index is null, while the actual metadata is in the /Posts/List partial view result

I went with this in my partial which renders the og:data ("_OpenGraphMetadata"):

@{
    OpenGraphModel openGraph = GetOpenGraphMetadata();
    if (openGraph != null)
    {
        @OpenGraphMetaProperty("title", openGraph.Title)
        @OpenGraphMetaProperty("description", openGraph.Description)
        @OpenGraphMetaProperty("url", openGraph.Url)
        @OpenGraphMetaProperty("image", openGraph.Image)
    }
}
@helper OpenGraphMetaProperty(string property, string value)
{
    if (!value.NullOrBlank())
    {
        <meta property="og:@property" content="@value" />
    }
}
@functions
{
    private OpenGraphModel GetOpenGraphMetadata()
    {
        IHasOpenGraphMetadata model = Model as IHasOpenGraphMetadata;
        if (model != null)
        {
            return model.OpenGraph;
        }
        return Context.Items[Constants.OpenGraphContextItem] as OpenGraphModel;
    }
}

I figure this is pretty decent, try to extract the metadata from the actual model, and if the interface is not implemented, then access the HttpContext and look for the metadata there. The question now is, how should I be putting this metadata in the HttpContext?

I don't really want to pollute my action methods with calls like:

HttpContext.Items[Constants.OpenGraphContextItem] = model.OpenGraph;

But what other options do I have? Should I be doing this in a global action filter? a result filter? Is there an alternative to these options?

Update
It doesn't seem possible to do this in an action filter, the way I figured out I could do this was overriding the base controller's PartialView, and both View overloads, but this seems like a really unpolished approach, there must be a better way to accomplish this.

4

0 回答 0