Is it possible to record a generated ordered sequence of numbers spanning a content page and the main page using MVC / Razor?

The following sample code is a simplified version of the setting that we use for ads on our pages, where we need to write a “position” on each ad tag. Position numbers should be sequentially from top to bottom, starting with 1. The problem is that some ad tags are defined on the wizard / layout page, while others are defined in the page layout.

See the following code example:

_Layout.cshtml:

<!DOCTYPE html>
<html>
<head><title>Ad Position Test</title></head>

<body>
  @Html.SequentialNumber()
  @RenderBody()
  @Html.SequentialNumber()
</body>
</html>

Index1.cshtml:

@{Layout = "~/Views/Shared/_Layout.cshtml";}

@Html.SequentialNumber()

Index2.cshtml:

@{Layout = "~/Views/Shared/_Layout.cshtml";}

@Html.SequentialNumber()
@Html.SequentialNumber()

Helpers.cs

public static class HtmlHelperExtensions
{
    public static HtmlString SequentialNumber(this HtmlHelper html)
    {
        var tile = (int)(html.ViewData["Tile"] ?? 1);
        html.ViewData["Tile"] = tile + 1;

        return new HtmlString(tile.ToString());
    }
}

The result of this installation for Index1.cshtml is "2 1 3" and for Index2.cshtml is "3 1 2 4". This, of course, is the result of executing the RenderBody method before executing the main content.

, , , , , "1 2 3" "1 2 3 4" ?

+3
2

*

* , , . , , . HTTP IIS7 , . .

, , , . , , ( , , ).

, HTML, - , :

public static class HtmlHelperExtensions
{
    public static HtmlString SequentialNumber(this HtmlHelper html)
    {
        //Any sufficiently unique string would do
        return ":{ad_sequence}";
    }
}

ASP.NET MVC , . , HomeController Index(), :

[AdSequencePostProcessingFilter]
public class HomeController : Controller
{
}

public class HomeController : Controller
{
    [AdSequencePostProcessingFilter]
    public ActionResult Index()
    {
        return View();
    }
}

ASP.NET MVC 3 , :

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalFilters.Filters.Add(new AdSequencePostProcessingFilterAttribute());
    }
}

, . .

AdSequencePostProcessingFilterAttribute ( ):

public class AdSequencePostProcessingFilterAttribute : ActionFilterAttribute
{
    private Stream _output;
    private const string AdSequenceMarker = ":{ad_sequence}";
    private const char AdSequenceStart = ':';

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //Capture the original output stream;
        _output = filterContext.HttpContext.Response.Filter;
        filterContext.HttpContext.Response.Flush();
        filterContext.HttpContext.Response.Filter = new CapturingResponseFilter(filterContext.HttpContext.Response.Filter);
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        //Get the emitted markup
        filterContext.HttpContext.Response.Flush();
        CapturingResponseFilter filter = 
            (CapturingResponseFilter)filterContext.HttpContext.Response.Filter;
        filterContext.HttpContext.Response.Filter = _output;
        string html = filter.GetContents(filterContext.HttpContext.Response.ContentEncoding);

        //Replace the marker string in the markup with incrementing integer
        int adSequenceCounter = 1;
        StringBuilder output = new StringBuilder();
        for (int i = 0; i < html.Length; i++)
        {
            char c = html[i];
            if (c == AdSequenceStart && html.Substring(i, AdSequenceMarker.Length) == AdSequenceMarker)
            {
                output.Append(adSequenceCounter++);
                i += (AdSequenceMarker.Length - 1);
            }
            else 
            {
                output.Append(c);
            }
        }

        //Write the rewritten markup to the output stream
        filterContext.HttpContext.Response.Write(output.ToString());
        filterContext.HttpContext.Response.Flush();
    }
}

, :

class CapturingResponseFilter : Stream
{
    private Stream _sink;
    private MemoryStream mem;

    public CapturingResponseFilter(Stream sink)
    {
        _sink = sink;
        mem = new MemoryStream();
    }

    // The following members of Stream must be overriden.
    public override bool CanRead { get { return true; } }
    public override bool CanSeek  { get { return false; } }
    public override bool CanWrite { get { return false; } }
    public override long Length { get { return 0; } }
    public override long Position { get; set; }

    public override long Seek(long offset, SeekOrigin direction)
    {
        return 0;
    }

    public override void SetLength(long length)
    {
        _sink.SetLength(length);
    }

    public override void Close()
    {
        _sink.Close();
        mem.Close();
    }

    public override void Flush()
    {
        _sink.Flush();
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return _sink.Read(buffer, offset, count);
    }

    // Override the Write method to filter Response to a file. 
    public override void Write(byte[] buffer, int offset, int count)
    {
        //Here we will not write to the sink b/c we want to capture

        //Write out the response to the file.
        mem.Write(buffer, 0, count);
    }

    public string GetContents(Encoding enc)
    {
        var buffer = new byte[mem.Length];
        mem.Position = 0;
        mem.Read(buffer, 0, buffer.Length);
        return enc.GetString(buffer, 0, buffer.Length);
    }
}

voilà, , : P

+3

SequentialNumber(), RenderBody, . , , : P

:

public static class HtmlHelperExtensions
{
    public static HtmlString SequentialNumber(this HtmlHelper html,int? sequence)
    {
        if(sequence!=null)
        {   
             var tile = sequence;
             html.ViewData["Tile"] = sequence + 1;
        }
        else
        {
             var tile = (int)(html.ViewData["Tile"] ?? 1);
             html.ViewData["Tile"] = tile + 1;
        }
        return new HtmlString(tile.ToString());
    }
}

<!DOCTYPE html>
<html>
<head><title>Ad Position Test</title></head>

<body>
  @Html.SequentialNumber(1)
  @Html.SequentialNumber(2)
  @RenderBody()
  @Html.SequentialNumber(null)
</body>

@{Layout = "~/Views/Shared/_Layout.cshtml";}

@Html.SequentialNumber(null)
@Html.SequentialNumber(null)

, , , , .

0

Source: https://habr.com/ru/post/1793619/


All Articles