I have two classes, none of which I can change in any way:
Class 1: Takes a TextWriter as constructor parameter and uses it as an output stream.
Class 2: Provides a method WriteLine(string).
I need an adapter, such that all the output of Class1 is written to Class2. Therefore I started an adapter which extends TextWriter and buffers incoming text, flushing it to the class2 instance as soon as a new line arrives.
However, there are many and more methods in TextWriter - which should I implement? Output in Class1 is string only.
According to MSDN one should override Write(char) as a minimum, however, this enforces me to do all the \r\n new line handling myself as well...
Q1: Do you know of a better way to reach my goal?
Q2: If no, which TextWriter methods should I override to have minimum implementation effort.
Implementing Write(char) on your TextWriter derived class is all you need to do. If somebody calls WriteLine on your new class, the base class WriteLine method is called. It will do the right thing: call your Write method with the individual \r and \n characters.
Actually, WriteLine(string) looks something like this:
void WriteLine(string s)
{
Write(s);
Write("\r\n");
}
And Write(string) is, in effect:
foreach (char c in s)
{
Write(c);
}
All of the Write methods in TextWriter resolve to something that calls Write(char) in a loop.
You really don't have to implement anything else. Just override Write(char) and plug it in. It will work.
You can override those other methods. Doing so will make your class a little more efficient (faster). But it's not required. I say do the simplest thing you can. Then, if you determine after profiling that your custom writer is too slow, override other methods as necessary.
Here's a minimal TextWriter descendant:
public class ConsoleTextWriter: TextWriter
{
public override void Write(char value)
{
Console.Write(value);
}
public override Encoding Encoding
{
get { return Encoding.Default; }
}
}
If I then write:
using (var myWriter = new ConsoleTextWriter())
{
myWriter.Write("hello, world");
myWriter.WriteLine();
myWriter.WriteLine();
myWriter.WriteLine("Goodbye cruel world.");
myWriter.Write("Fee fie foe foo!");
}
The output is:
hello, world
Goodbye cruel world.
Fee fie foe foo!
I'm adding another answer because I couldn't get the above answer to work!
In my experience, I must override WriteLine() and WriteLine(string) in order for those functions to work.
Here's an example that can be used to write a web page as a long-running task goes on. BTW, the HttpResponse object is from ASP.net MVC.
public class WebConsoleWriter : TextWriter
{
HttpResponseBase Response { get; set; }
bool FlushAfterEveryWrite { get; set; }
bool AutoScrollToBottom { get; set; }
Color BackgroundColor { get; set; }
Color TextColor { get; set; }
public WebConsoleWriter(HttpResponseBase response, bool flushAfterEveryWrite, bool autoScrollToBottom)
{
Response = response;
FlushAfterEveryWrite = flushAfterEveryWrite;
AutoScrollToBottom = autoScrollToBottom;
BackgroundColor = Color.White;
TextColor = Color.Black;
}
public WebConsoleWriter(HttpResponseBase response, bool flushAfterEveryWrite, bool autoScrollToBottom, Color backgroundColor, Color textColor)
{
Response = response;
FlushAfterEveryWrite = flushAfterEveryWrite;
AutoScrollToBottom = autoScrollToBottom;
BackgroundColor = backgroundColor;
TextColor = textColor;
}
public virtual void WritePageBeforeStreamingText()
{
string headerFormat =
#"<!DOCTYPE html>
<html>
<head>
<title>Web Console</title>
<style>
html {{
background-color: {0};
color: {1};
}}
</style>
</head>
<body><pre>";
string backgroundColorHex = ColorTranslator.ToHtml(BackgroundColor);
string foregroundColorHex = ColorTranslator.ToHtml(TextColor);
Response.Write(string.Format(headerFormat, backgroundColorHex, foregroundColorHex));
// Add a 256 byte comment because I read that some browsers will automatically buffer the first 256 bytes.
Response.Write("<!--");
Response.Write(new string('*', 256));
Response.Write("-->");
Response.Flush();
}
public virtual void WritePageAfterStreamingText()
{
Response.Write("</pre></body></html>");
}
public override void Write(string value)
{
string encoded = Encode(value);
Response.Write(encoded);
if (FlushAfterEveryWrite)
Response.Flush();
}
public override void WriteLine(string value)
{
Response.Write(Encode(value) + "\n");
if (AutoScrollToBottom)
ScrollToBottom();
if (FlushAfterEveryWrite)
Response.Flush();
}
public override void WriteLine()
{
Response.Write('\n');
if (AutoScrollToBottom)
ScrollToBottom();
if (FlushAfterEveryWrite)
Response.Flush();
}
private string Encode(string s)
{
return s.Replace("&", "&").Replace("<", "<").Replace(">", ">");
}
public override void Flush()
{
Response.Flush();
}
public void ScrollToBottom()
{
Response.Write("<script>window.scrollTo(0, document.body.scrollHeight);</script>");
}
public override System.Text.Encoding Encoding
{
get { throw new NotImplementedException(); }
}
}
Related
I would like to perform testing for below abstract Streaming class which has two virtual methods that are overridden in the Asset class in same project. Here the SerializeBinary() method converts an object into binary streams and DeserializeFromBinary() method does the opposite of SerializeBinary().
How to write test class for comparing both using Moq?
I go through from here:
This is part of my code:
Streaming class:
public abstract class Streaming
{
private static int _streamingIDExponent = 41;
public const string MonthLookup = "ABCDEFGHIJK";
public const string ExpiryStringFormat = "ddMMMyyyy";
public const double DefaultTicksPerPoint = 3;
private long _StreamingID;
private int _minQty = DefaultMinimumQty;
public virtual void SerializeBinary(BinaryStreamWriter binaryStreamWriter)
{
binaryStreamWriter.Write(_StreamingID);
binaryStreamWriter.Write(_ex_StreamingID);
binaryStreamWriter.Write(_minQty);
binaryStreamWriter.Write(_extendedProperties.Count);
foreach (KeyValuePair<StreamingPropertyName, StreamingProperty> dictionaryEntry in _extendedProperties)
{
dictionaryEntry.Value.SerializeBinary(binaryStreamWriter);
}
}
public virtual bool DeserializeFromBinary(BinaryStreamReader binaryStreamReader, out string errorString)
{
errorString = string.Empty;
try
{
_StreamingID = binaryStreamReader.ReadInt64();
_exStreamingID = binaryStreamReader.ReadInt64();
_minQty = binaryStreamReader.ReadInt32();
}
catch (Exception oEx)
{
errorString = oEx.Message;
}
return string.IsNullOrEmpty(errorString);
}
Asset class:
public class Asset : Streaming
{
public override void SerializeBinary(BinaryStreamWriter binaryStreamWriter)
{
base.SerializeBinary(binaryStreamWriter);
}
public override bool DeserializeFromBinary(BinaryStreamReader binaryStreamReader, out string errorString)
{
if (!base.DeserializeFromBinary(binaryStreamReader, out errorString))
return false;
try
{
return true;
}
catch (Exception oEx)
{
errorString = oEx.Message;
return false;
}
}
}
you can create a new Mock of your Streaming class like this:
var streamingMock = new Mock<Streaming> { CallBase = true };
The call base is important because it will then execute the implemented code in your concrete class.
Then you can call the methods via the Object property:
streamingMock.Object.SerializeBinary(...);
Hope this helps
There's no good way to test the interaction between Asset and Streaming with Moq in your current implementation. However, if you're willing to change the implementation of the classes just a bit, you can get it done. Basically, you'll want to move the logic of the Streaming class's methods into new methods, and you can then mock those.
public abstract class Streaming
{
public virtual void SerializeBinaryCore(BinaryStreamWriter writer)
{
// put the logic from your original SerializeBinary method here...
}
public virtual bool DeserializeFromBinaryCore(BinaryStreamReader reader, out string errorMessage)
{
// put the logic from your original DeserializeFromBinary method here...
}
public abstract void SerializeBinary(BinaryStreamWriter writer);
public abstract bool DeserializeFromBinary(BinaryStreamReader reader, out string errorMessage);
}
And then tweak your Asset class as follows:
public class Asset : Streaming
{
public override void SerializeBinary(BinaryStreamWriter writer)
{
SerializeBinaryCore(writer);
}
public override void DeserializeFromBinary(BinaryStreamReader reader, out string errorMessage)
{
var result = DeserializeFromBinaryCore(reader, out errorMessage);
// put the rest of your Asset deserialization logic here...
}
}
In your test, you need to create a Mock<Asset> { CallBase = true }, and then create setups for the SerializeBinaryCore and DeserializeFromBinaryCore methods.
I have a serialization task where different parts and pieces of my object model know how to emit their own string segments, but I'd like the option to emit them using .Append against a common StringBuilder object. On the theory that we should not pass around our private objects for others to use indiscriminately, here's a class that wraps a StringBuilder to make it "append-only" for use in my scenario.
public sealed class AppendOnlyStringBuilder {
private readonly StringBuilder _stringBuilder;
public AppendOnlyStringBuilder(StringBuilder stringBuilder)
{
_stringBuilder = stringBuilder;
}
public AppendOnlyStringBuilder Append<T>(T value)
{
_stringBuilder.Append(value);
return this;
}
}
If my code inside of the different chunks of my model right now all look similar to this:
// Chunk1 class
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb
.Append(_prop1.Value)
.Append(_prop2.Value)
.Append(_prop3.Value);
return sb.ToString();
}
And these ToString methods are called from the main routine's serialization method like so:
// MainObject class
Chunk1 _chunk1;
Chunk2 _chunk2;
Chunk3 _chunk3;
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb
.Append(_chunk1.ToString()) // ToString may be unnecessary here
.Append(_chunk2.ToString())
.Append(_chunk3.ToString());
return sb.ToString();
}
How can I elegantly switch to passing around a single AppendOnlyStringBuilder for use in all these chunk classes instead of each one internally creating a new StringBuilder and doing ToString?
I'd like it to be used something like this:
// MainObject class
public override string ToString() {
StringBuilder sb = new StringBuilder();
AppendOnlyStringBuilder aosb = new AppendOnlyStringBuilder(sb);
aosb
.Append(_chunk1)
.Append(_chunk2)
.Append(_chunk3);
return sb.ToString();
}
An extension method is a natural way to get this syntax, but I'm running into problems due to the extension method needing to be static and thus not able to access private parts of the Chunk classes. I'd like to keep the same ToString in the chunk classes so they can still do their normal "serialize just me" thing, but I'd also like for them to be able to optionally append to my common AppendOnlyStringBuilder.
I guess I could do this:
_chunk1.AppendTo(aosb);
_chunk2.AppendTo(aosb);
_chunk3.AppendTo(aosb);
But something about that bugs me--I'd like to use a fluent interface that begins with the AppendOnlyStringBuilder object as in my example previously.
Ok, here goes:
using System.IO;
abstract class BaseClass
{
protected abstract void WriteToTextWriter(TextWriter textWriter);
public void SerializeTo(TextWriter textWriter)
{
WriteToTextWriter(textWriter);
}
public sealed override string ToString()
{
var writer = new StringWriter();
SerializeTo(writer);
return writer.ToString();
}
}
abstract class ChunkBase : BaseClass
{
private readonly string _index;
protected ChunkBase(string index)
{
_index = index;
}
protected sealed override void WriteToTextWriter(TextWriter textWriter)
{
textWriter.Write("Chunk");
textWriter.Write(_index);
}
}
class Chunk1 : ChunkBase { public Chunk1() : base("1") { } }
class Chunk2 : ChunkBase { public Chunk2() : base("2") { } }
class Chunk3 : ChunkBase { public Chunk3() : base("3") { } }
class ClassWithChunks : BaseClass
{
private readonly Chunk1 _chunk1 = new Chunk1();
private readonly Chunk2 _chunk2 = new Chunk2();
private readonly Chunk3 _chunk3 = new Chunk3();
protected override void WriteToTextWriter(TextWriter textWriter)
{
_chunk1.SerializeTo(textWriter);
_chunk2.SerializeTo(textWriter);
_chunk3.SerializeTo(textWriter);
}
}
Now, if you want chaining, you could do this:
class Chainable
{
private readonly TextWriter _textWriter;
public Chainable(TextWriter textWriter)
{
_textWriter = textWriter;
}
public Chainable Write(BaseClass obj)
{
obj.SerializeTo(_textWriter);
return this;
}
}
Then, your WriteToTextWriter could be, for example, this:
public override void WriteToTextWriter(TextWriter textWriter)
{
new Chainable(textWriter)
.Write(_chunk1)
.Write(_chunk2)
.Write(_chunk3);
}
I'm not sure it's worth it: the code is certainly cleaner, but it will be harder for someone (including your future self) to decipher, because of the additional layer of complexity.
Edit: Making the abstract method protected seems to add little here, but in production code, the extra layer could well be helpful. You'll want to add some switches, too, to handle formatting and the like.
Seems like the ideal candidate for the adapter pattern.
(untested code)
public interface IAppendOnly
{
void Append(string content);
}
public class AppendOnlyStringBuilder : IAppendOnly
{
private StringBuilder _stringBuilder = new StringBuilder()
public void Append(string content)
{
_stringBuilder.Append(content);
}
public override string ToString()
{
return _stringBuilder.ToString();
}
}
public class Chunk
{
public void AppendTo(IAppendOnly appendOnly)
{
appendOnly.Append("My Content");
}
}
Then each Chunk works without the knowledge of how the interface was instantiated:
_chunk1.AppendTo(aosb);
_chunk2.AppendTo(aosb);
_chunk3.AppendTo(aosb);
But something about that bugs me--I'd like to use a fluent interface that begins with the AppendOnlyStringBuilder object as in my example previously.
So with this requirement (minus the unnecessary AppendOnlyStringBuilder class) you'd then switch the interface direction.
public interface IGetString
{
string GetString();
}
public Chunk : IGetString
{
public string GetString()
{
return "MyContent";
}
}
public static class StringBuilderExtensions
{
public static StringBuilder AppendFrom(this StringBuilder instance
, IGetString getString)
{
instance.Append(getString.GetString())
return instance;
}
}
Then it's Fluent:
var sb = new StringBuilder;
var a = new Chunk();
var b = new Chunk();
sb.AppendFrom(a).AppendFrom(b);
If you want only one instatiated object of a type you could use the singleton pattern (Google will give you many exampels)
If you have a global object (something like a "myApplication"-class) you could offer this there.
Other way is a static class offering this singleton instance "from everywhere".
Your code would append directly to this one instance...
Hope this helps
Does anybody have any idea about how to output minified HTML and JavaScript from the Razor engine while keeping custom coding styles?
For example: i want the following code:
<div
#if (Model.Name != string.Empty)
#:id="#Model.Name"
>
</div>
To be outputted as <div id="DivId"></div> .
Look at http://arranmaclean.wordpress.com/2010/08/10/minify-html-with-net-mvc-actionfilter/.
there is an example for creating custom action filter witch clear html from WhiteSpaces
Update: The source code quoted from above.
The stream class for removing "blanks"
using System;
using System.IO;
using System.Text;
using System.Web.Mvc;
using System.Text.RegularExpressions;
namespace RemoveWhiteSpace.ActionFilters
{
public class WhiteSpaceFilter : Stream
{
private Stream _shrink;
private Func<string, string> _filter;
public WhiteSpaceFilter(Stream shrink, Func<string, string> filter)
{
_shrink = shrink;
_filter = filter;
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return true; } }
public override bool CanWrite { get { return true; } }
public override void Flush() { _shrink.Flush(); }
public override long Length { get { return 0; } }
public override long Position { get; set; }
public override int Read(byte[] buffer, int offset, int count)
{
return _shrink.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _shrink.Seek(offset, origin);
}
public override void SetLength(long value)
{
_shrink.SetLength(value);
}
public override void Close()
{
_shrink.Close();
}
public override void Write(byte[] buffer, int offset, int count)
{
// capture the data and convert to string
byte[] data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
string s = Encoding.Default.GetString(buffer);
// filter the string
s = _filter(s);
// write the data to stream
byte[] outdata = Encoding.Default.GetBytes(s);
_shrink.Write(outdata, 0, outdata.GetLength(0));
}
}
}
The ActionFilter class:
public class WhitespaceFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
var response = filterContext.HttpContext.Response;
response.Filter = new WhiteSpaceFilter(response.Filter, s =>
{
s = Regex.Replace(s, #"\s+", " ");
s = Regex.Replace(s, #"\s*\n\s*", "\n");
s = Regex.Replace(s, #"\s*\>\s*\<\s*", "><");
s = Regex.Replace(s, #"<!--(.*?)-->", ""); //Remove comments
// single-line doctype must be preserved
var firstEndBracketPosition = s.IndexOf(">");
if (firstEndBracketPosition >= 0)
{
s = s.Remove(firstEndBracketPosition, 1);
s = s.Insert(firstEndBracketPosition, ">");
}
return s;
});
}
}
And in the end the usage of above:
[HandleError]
[WhitespaceFilter]
public class HomeController : Controller
{
...
}
Maybe you looking for Meleze.Web
Meleze.Web is a toolbox to optimize ASP.NET MVC 3.0 and MVC 4.0 applications.
It provides HTML, JS and CSS minification of Razor views and caching of the returned pages.
Darin Dimitrov write about it here: ASP.Net MVC Razor Views - Minifying HTML at build time
But I think enabling gzip is better solution, you could read about it here: Minify HTML output from an ASP.Net MVC Application
I don't think that there is any way to achieve that. To avoid the tag soup I usually prefer writing custom helpers:
#using(Html.MyDiv(Model.Name))
{
... put the contents of the div here
}
and here's how the custom helper might look like:
public static class HtmlExtensions
{
private class Div : IDisposable
{
private readonly ViewContext context;
private bool disposed;
public Div(ViewContext context)
{
this.context = context;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
this.disposed = true;
context.Writer.Write("</div>");
}
}
}
public static IDisposable MyDiv(this HtmlHelper html, string id)
{
var div = new TagBuilder("div");
if (!string.IsNullOrEmpty(id))
{
div.GenerateId(id);
}
html.ViewContext.Writer.Write(div.ToString(TagRenderMode.StartTag));
return new Div(html.ViewContext);
}
}
Alternatively you could also do a tag soup:
<div#Html.Raw(Model.Name != string.Empty ? string.Format(" id=\"{0}\"", Html.AttributeEncode(Model.Name)) : string.Empty)>
</div>
For anybody interested in this, I built a simple HTML minification library that can be used with MVC 5:
https://github.com/tompazourek/RazorHtmlMinifier.Mvc5
It operates in compile-time instead of runtime, so it doesn't add any performance overhead. The minification is very simple (just replaces lots of spaces with one space).
Even with GZIP enabled on top of the minified HTML, it can still reduce the payload size.
I have the following script transformation component.
public class ScriptMain : UserComponent
{
Regex findCOMMAexp, findAmpersandExp, findANDExp;
public override void PreExecute()
{
base.PreExecute();
//extract and compress publishers.
findANDExp = new Regex(#"(\w+\s*)+(?=\band\b)",RegexOptions.Compiled);
findCOMMAexp = new Regex(#"(\w+\s*)+[,]\s*(\w+\s*)",RegexOptions.Compiled);
findAmpersandExp = new Regex(#"(\w+\s*)+[&]\s*(\w+\s*)",RegexOptions.Compiled);
}
public override void PostExecute()
{
base.PostExecute();
}
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
Row.CompressedPublisher = compressPublisher(Row.F018Publisher);
}
public String compressPublisher(String str)
{
Match match;
if (str.Contains("/"))
{
return str.Substring(0, str.IndexOf(('/')));
}
else if ((match = findANDExp.Match(str)).Success)
{
return match.ToString();
}
else if ((match = findCOMMAexp.Match(str)).Success)
{
return Regex.Replace(str, ",", "");
}
else
{
return str;
}
}
}
The 3 Regex objects are defined in the main class, initialized in the PreExecute(), and used in a method called by the ProcessInputRow. I have a database source that pulls in a single varchar(45) string, defined as F018Publisher. I stopped this task after 10 mins, while trying to parse 9k entries. What is going wrong?
Thanks.
I wrapped this into a C# commandline app and passed ABCDEFGHIJKLMOPQRSTUVWXYZ01234567890123456789 as a parameter to compressPublisher and it never returned from this check else if ((match = findANDExp.Match(str)).Success)
Same comment posted to twitter as well
The following example code is a simplified version of a setup we use for ads on our pages where we have to write a "position" number on each ad tag. The position numbers must be sequential from top to bottom starting with 1. The problem is that some of the ad tags are defined in the master/layout page and others are defined within the page markup.
Please see the following example code:
_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 output of this setup for Index1.cshtml is: "2 1 3" and for Index2.cshtml it is: "3 1 2 4". This is of course the result of the RenderBody method being executed before the master content is executed.
So question is, how do you output a correctly ordered sequence of numbers that spans both the master page and the content page such that the output will be "1 2 3" and "1 2 3 4" respectively?
You can achieve this through the cunning use of action filters*
* I would like to preface my answer with the fact that I can't necessarily recommend you actually use the method I am about to post. But I was curious whether this could be done, so I did. I've discussed a more reasonable solution using managed HTTP handlers in IIS7 in the comments below, see also this awesome tutorial.
Because, as you have discovered, nested views are rendered in their nesting order, you can't achieve the required effect during the normal view rendering phase. But after the view has been rendered, there's nothing stopping us from modifying the resulting markup (except perhaps common sense).
So first, let's change the HTML helper to emit some kind of marker we can replace:
public static class HtmlHelperExtensions
{
public static HtmlString SequentialNumber(this HtmlHelper html)
{
//Any sufficiently unique string would do
return ":{ad_sequence}";
}
}
In ASP.NET MVC you can decorate controller classes and controller actions with action filter attributes to execute code before and after the actions have been executed. For example, here we will define an action filter to handle all methods inside the HomeController, and only the Index() action, respectively:
[AdSequencePostProcessingFilter]
public class HomeController : Controller
{
}
public class HomeController : Controller
{
[AdSequencePostProcessingFilter]
public ActionResult Index()
{
return View();
}
}
In ASP.NET MVC 3 we can also have global filters which apply to all controller actions in your application:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalFilters.Filters.Add(new AdSequencePostProcessingFilterAttribute());
}
}
You can decide to apply the filter on individual actions, controllers or globally. Your choice.
Now we'll need to define the AdSequencePostProcessingFilterAttribute filter (based on this caching filter class):
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();
}
}
We'll also need a sink where we can capture the output:
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);
}
}
And voilĂ , we have the sequence increading in document order :P
You could force the numbers on the SequentialNumber() function that comes before the RenderBody and then start the sequence from there. I guess there is a more generic solution, but cant think of any right now :P
Edit
What about this:
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());
}
}
And then
<!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)
I'm not sure if you can be more generic, somehow you have to tell your helper that one call have more priority that the other.