I'm trying to compile small fragments of C# into JavaScript using the Script# compiler.
But I don't get anything in return, GetStream() in my MemoryStreamSource is not even being called, so I must be doing something wrong.
Here's my code:
CodeScriptCompiler csc = new CodeScriptCompiler();
return csc.CompileCSharp("String.IsNullOrWhiteSpace(Model.MobilePhoneNumber)");
CodeScriptCompiler.cs
using System;
using System.Collections.Generic;
using ScriptSharp;
namespace CodeToScriptCompiler
{
public class CodeScriptCompiler
{
ScriptCompiler sc = new ScriptCompiler();
public string CompileCSharp(string csharpCode)
{
string errorMessages = String.Empty;
CompilerOptions options = new CompilerOptions();
options.Defines = new List<string>();
options.References = new List<string>();
options.References.Add("System.dll");
options.Resources = new List<IStreamSource>();
options.Sources = new List<IStreamSource>();
options.Sources.Add(new MemoryStreamSource(csharpCode));
options.TemplateFile = new MemoryStreamSource(csharpCode);
MemoryStreamDestination output = new MemoryStreamDestination();
options.ScriptFile = output;
if (!options.Validate(out errorMessages))
{
return errorMessages;
}
return output.GetCompiledCode();
}
}
}
MemoryStreamSource.cs
using System.IO;
using System.Text;
using ScriptSharp;
namespace CodeToScriptCompiler
{
public class MemoryStreamSource : IStreamSource
{
private string _code;
private MemoryStream _memoryStream;
public MemoryStreamSource(string code)
{
this._code = code;
}
public string Name
{
get { return "InMemoryCode"; }
}
public string FullName
{
get { return "InMemoryCode"; }
}
public void CloseStream(Stream stream)
{
stream.Close();
}
public Stream GetStream()
{
this._memoryStream = new MemoryStream(Encoding.ASCII.GetBytes(this._code));
return this._memoryStream;
}
}
}
MemoryStreamDestination.cs
using System;
using System.IO;
using ScriptSharp;
namespace CodeToScriptCompiler
{
public class MemoryStreamDestination : IStreamSource
{
private MemoryStream _memoryStream;
private string _compiledCode;
public string Name
{
get { return "MemoryStreamDestination"; }
}
public string FullName
{
get { return "MemoryStreamDestination"; }
}
public void CloseStream(Stream stream)
{
if (String.IsNullOrWhiteSpace(this._compiledCode))
{
this._compiledCode = this.GetCompiledCode();
}
stream.Close();
}
public Stream GetStream()
{
this._memoryStream = new MemoryStream();
return this._memoryStream;
}
public string GetCompiledCode()
{
if (!String.IsNullOrWhiteSpace(this._compiledCode))
{
return this._compiledCode;
}
if (this._memoryStream != null)
{
using (StreamReader sr = new StreamReader(this._memoryStream))
{
return sr.ReadToEnd();
}
}
return String.Empty;
}
}
}
Some things I see potentially problematic.
TemplateFile is set to a c# code stream. Leave it unset, since that is not a valid template.
References should include the script# mscorlib, and furthermore, only full paths to valid script# assemblies. System.dll is not a script# assembly.
Before you read from the MemoryStream, you need to set the stream position back to the start, otherwise it is at the end after the compiler has written to it, and there is nothing more to read.
Not seeing a call to Compile on the Compiler instance you created, passing in the options instance. My guess is you did do that, just not there in the stack overflow snippet.
You probably should also implement IErrorHandler and pass that to the compiler to get error messages should they occur, once you have the basic thing working.
For reference you can also look at the unit tests at https://github.com/nikhilk/scriptsharp/tree/master/tests/ScriptSharp/Core which does something similar.
Note that you'll need a valid c# source file, rather than a single standalone expression. You can however likely deal with that by stripping off stuff from the start and end of the resulting script to get the script for just the expression you care about.
Hope that helps.
I am certainly interested/curious to understand how you're using this, and where you're compiling c# to script dynamically...
Related
Preface
I have created an ASP.NET Code Web API using Visual Studio 2022 to familiarise myself with the topic of "Web APIs".
I have converted the project to .NET 5.
In the MyControllers.cs I have so far code for a Get and for a Post request.
I have removed the WeatherForecast.cs created by Visual Studio. I have also set in the launchSettings.json that the browser jumps to MyController from the beginning.
To practice Dependency Injection, I added another project called TextRepository (a class library) to the assembly. I had written a text file with another Visual Studio project that contains the numbers from 0–99. This text file is read in and returned in the Get method of MyController.cs. Now the numbers are displayed in the browser when called. I had also included the interface INumberRepository.
To practise the whole thing again, I created another repository: ImageRepository. The aim is to find all pictures in the folder Pictures and store them in a List. To do this, I downloaded System.Drawing.Common from the NuGet package manager.
Question for you:
I am still struggling a bit to request the API in the browser for different purposes. I still want to use the call https://localhost:44355/api/My for displaying the numbers in the browser, i.e., the Get method. How can I make it so that I use a different link to transfer the image data? I am concerned with the call to the API – do I have to write a second Get function? – And about transferring the bytes of the images.
If anyone wonders what the images are: I have created 2 test images for this purpose (1920 pixels ×1080 pixels).
WebApplication2
in Startup.cs
services.AddScoped<TextRepository.INumberRepository, TextRepository.NumberTextFileRepository>();
services.AddScoped<ImageRepository.IImageTransferRepository, ImageRepository.ImageTransferRepository>();
MyController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using TextRepository;
using ImageRepository;
namespace WebApplication2.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
private readonly INumberRepository numberRepository;
private readonly IImageTransferRepository imageRepository;
public MyController(INumberRepository numberRepository, IImageTransferRepository imageTransferRepository)
{
this.numberRepository = numberRepository;
this.imageRepository = imageTransferRepository;
}
[HttpGet]
public ActionResult<List<int>> Get()
{
List<int> numbers = this.numberRepository.GetNumbers();
List<System.Drawing.Bitmap> foundImages = this.imageRepository.GetImages();
return Ok(numbers);
}
[HttpPost]
public IActionResult Post([FromBody] DataTransferObject transferObject)
{
return Ok(transferObject.PassedString + $" {transferObject.Zahl}");
}
}
}
TextRepository
TextFileParser.cs
using System;
using System.Collections.Generic;
using System.IO;
namespace TextRepository
{
public class TextFileParser
{
public static List<int> ReadAllData(string path)
{
if (!File.Exists(path))
{
throw new FileNotFoundException(path);
}
string[] allLines = System.IO.File.ReadAllLines(path);
if (allLines == null)
{
throw new Exception("War null");
}
if (allLines.Length < 1)
{
throw new Exception("Die Datei enthält 0 Zeilen.");
}
if (allLines.Length == 1)
{
return new List<int>();
}
List<int> numbers = new List<int>();
for (int i = 1; i < allLines.Length; i++)
{
if (int.TryParse(allLines[i], out int result))
{
numbers.Add(result);
}
else
{
Console.WriteLine($"In der Textdatei, in Zeile {i + 1}, ist eine inkorrekte Zahl aufgetreten.");
continue;
}
}
return numbers;
}
}
}
NumberTextFileRepository
using System.Collections.Generic;
namespace TextRepository
{
public class NumberTextFileRepository : INumberRepository
{
public List<int> GetNumbers()
{
System.IO.DirectoryInfo Root = new System.IO.DirectoryInfo(System.IO.Directory.GetCurrentDirectory());
return TextFileParser.ReadAllData(Root.Parent.FullName + "\\Textdatei.txt");
}
}
}
INumberRepository.cs
using System.Collections.Generic;
namespace TextRepository
{
public interface INumberRepository
{
List<int> GetNumbers();
}
}
ImageTransferRepository
ImageTransferRepository.cs
using System;
using System.Collections.Generic;
namespace ImageRepository
{
public class ImageTransferRepository : IImageTransferRepository
{
public List<System.Drawing.Bitmap> GetImages()
{
return ImageTransfer.GetImagesFromFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures));
}
}
}
ImageTransfer.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ImageRepository
{
public class ImageTransfer
{
public static List<System.Drawing.Bitmap> GetImagesFromFolder(string path)
{
if (!Directory.Exists(path))
{
throw new FileNotFoundException(path);
}
List<FileInfo> fileInfos = new List<FileInfo>();
fileInfos.AddRange(new DirectoryInfo(path).EnumerateFiles().Where(f => IsValidFile(f)));
fileInfos = fileInfos.OrderBy(x => x.CreationTime).ToList(); // The newest image should be at the top of the list.
return (from FileInfo file in fileInfos select new System.Drawing.Bitmap(file.FullName)).ToList();
}
private static bool IsValidFile(FileInfo File)
{
return File.FullName.ToLower().EndsWith(".bmp") ^ File.FullName.ToLower().EndsWith(".jpeg") ^ File.FullName.ToLower().EndsWith(".jpg") ^ File.FullName.ToLower().EndsWith(".png");
}
}
}
IImageTransferRepository.cs
using System.Collections.Generic;
using System.Drawing;
namespace ImageRepository
{
public interface IImageTransferRepository
{
List<Bitmap> GetImages();
}
}
I still want to use the call https://localhost:44355/api/My for displaying the numbers in the browser, i.e., the Get method. How can I make it so that I use a different link to transfer the image data? I am concerned with the call to the API – do I have to write a second Get function? – And about transferring the bytes of the images.
If you want to return List<int> numbers and List<System.Drawing.Bitmap> foundImages together,you can try to create a class which contains the two lists.Or you need to write a second Get function.
public class TestModel {
public List<int> numbers { get; set; }
public List<System.Drawing.Bitmap> foundImages { get; set; }
}
Get function:
[HttpGet]
public ActionResult<TestModel > Get()
{
TestModel t=new TestModel();
t.numbers = this.numberRepository.GetNumbers();
t.foundImages = this.imageRepository.GetImages();
return Ok(t);
}
If you want to create a second Get function,here is the demo:
[HttpGet]
public ActionResult<List<int>> Get()
{
List<int> numbers = this.numberRepository.GetNumbers();
return Ok(numbers);
}
[HttpGet("foundImages")]//route will be https://localhost:44355/api/My/foundImages
public ActionResult<List<System.Drawing.Bitmap>> Get()
{
List<System.Drawing.Bitmap> foundImages = this.imageRepository.GetImages();
return Ok(foundImages);
}
I am trying to write a JSON helper class for a C# MVC app that returns a class instance of the type that is specified as a parameter. The intent of this is to simplify deserializing a JSON into a Model of the right type. the Unfortunately i am running into an error of:
'ModelType' is a variable but used as a type.
Here is the code I am using:
public ActionResult api_call() {
// Parse/Map request stream containing a JSON to a C# object
json_helper _o_json_helper = new json_helper();
pollread_read_request _request = _o_json_helper.parse_json_to_object(Assembly.GetExecutingAssembly().GetType("pollread_read_request"), Request.InputStream);
// Create a business logic instance
Pollmaker_business_logic _business_logic = new Pollmaker_business_logic();
// process request using business logic
List<pollread_read_response> _response = _business_logic.api_call(_request);
// return result
return Json(_response, JsonRequestBehavior.AllowGet);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
namespace Umbrella.Abstracts {
public class json_helper {
public Object parse_json_to_object(Type ClassModelType, System.IO.Stream InputStream) {
object _result = Activator.CreateInstance(ClassModelType);
try {
string _json_request = "";
using (System.IO.Stream _oRequestStream = InputStream) {
_oRequestStream.Seek(0, System.IO.SeekOrigin.Begin);
_json_request = new System.IO.StreamReader(_oRequestStream).ReadToEnd();
}
if (!String.IsNullOrEmpty(_json_request)) {
_result = Newtonsoft.Json.JsonConvert.DeserializeObject<ClassModelType> (_json_request);
}
} catch { }
return _result;
}
public json_helper() {}
}
}
Use the non-generic overload of DeserializeObject.
_result = Newtonsoft.Json.JsonConvert.DeserializeObject(_json_request, ClassModelType);
Have you also tried sending it only the assembly name and type name?
object _result = Activator.CreateInstance(ClassModelType.Assembly.FullName, ClassModelType.Name);
I am trying to add support for System.Web.Mvc.HtmlHelper to a CLI app for compiling Razor templates, but although it compiles it fails at runtime with:
System.TypeLoadException: Could not load type 'HtmlHelper`1' from assembly '/Users/oligofren/src/razor-cli/build/System.Web.Mvc.dll'.
How should I proceed in fixing this?
I am not well versed in the core of .NET (here in Mono version), so I can't say if I have done anything wrong here. I have added all the assemblies to the build folder (where the exe ends up) and I also try to manually load the required assemblies before RazorEngine tries to compile the assemblies.
How can I resolve this?
Full source code
// See also tips on building cli apps with razorengine: https://github.com/Antaris/RazorEngine/blob/master/src/source/RazorEngine.Hosts.Console/RazorEngine.Hosts.Console.csproj
using System;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using Moq;
using System.IO;
using Newtonsoft.Json.Linq;
using RazorEngine;
using RazorEngine.Templating; // For extension methods.
using RazorEngine.Configuration;
using RazorEngine.Text;
public class RazorCli
{
static public void Main (string[] args)
{
CheckCommandLine(args);
string template = ReadFile(args[0]);
JObject model = ParseModel(args[1]);
// try to load the required assemblies
//http://stackoverflow.com/a/23496144/200987
System.Reflection.Assembly.Load("System.Web");
System.Reflection.Assembly.Load("System.Web.Mvc");
var result = CompileTemplate(template, model);
Console.WriteLine (result);
}
private static string CompileTemplate (string template, JObject model)
{
string res = "";
var config = new TemplateServiceConfiguration();
// You can use the #inherits directive instead (this is the fallback if no #inherits is found).
config.BaseTemplateType = typeof(MyClassImplementingTemplateBase<>);
try
{
using (var service = RazorEngineService.Create(config))
{
res = service.RunCompile(template, "templateKey", null, model);
}
}
catch( RazorEngine.Templating.TemplateCompilationException ex )
{
Console.WriteLine (ex);
System.Environment.Exit(1);
}
return res;
}
/* Cannot dispatch a dynamic object to extension methods */
private static JObject ParseModel(string fileName){
string json = ReadFile(fileName);
return JObject.Parse(json);
}
private static void CheckCommandLine(string[] args){
if(args.Length != 2){
Usage();
System.Environment.Exit(1);
}
}
private static void Usage(){
string usage = "Usage: razor-cli <partial.cshtml> <model.json>\n";
Console.WriteLine(usage);
}
private static String ReadFile(string filename)
{
string result;
using (StreamReader sr = new StreamReader(filename))
{
result = sr.ReadToEnd();
}
return result;
}
}
public class MyHtmlHelper
{
public IEncodedString Raw(string rawString)
{
return new RawString(rawString);
}
}
// https://antaris.github.io/RazorEngine/TemplateBasics.html
public abstract class MyClassImplementingTemplateBase<T> : TemplateBase<T>
{
public MyClassImplementingTemplateBase()
{
Html = MvcHelpers.CreateHtmlHelper<Object>();
}
public HtmlHelper Html { get; set; }
}
// Ripped straight from a SO Q/A
// http://stackoverflow.com/questions/17271688/mocking-viewcontext-to-test-validation-error-messages
public class MvcHelpers {
public static HtmlHelper<TModel> CreateHtmlHelper<TModel>(ViewDataDictionary dictionary = null)
{
if (dictionary == null)
dictionary = new ViewDataDictionary { TemplateInfo = new TemplateInfo() };
var mockViewContext = new Mock<ViewContext>(
new ControllerContext(
new Mock<HttpContextBase>().Object,
new RouteData(),
new Mock<ControllerBase>().Object),
new Mock<IView>().Object,
dictionary,
new TempDataDictionary(),
new Mock<TextWriter>().Object);
var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.Setup(v => v.ViewData).Returns(dictionary);
return new HtmlHelper<TModel>(mockViewContext.Object, mockViewDataContainer.Object);
}
}
Details on how I run this can be seen in the Makefile, if that helps.
Further details
Installed Mono 4.2.2.0 using Homebrew on OS X 10.11.4.
I am creating an Automation Framework using Selenium C#, currently I am working on the object repository part. So I would like to know what all types of files I can use as the Object Repository.Currently I am thinking of using either XML or Excel but I am not sure which one is better performance wise, so can any of you share your views on this and also let me know if there are any other options.
I am planning to use XmlDocument for reading xml and oledb connection for reading excel.
By Object repository i think you mean different elements, their locators and some other required attributes, because As far as i know selenium do not have concept of Object Repository inherently.
If so, you need to think about who is going to maintain this Repository,
with few thousand locators, rather than performance maintainability would be a major issue.
Also, think about making it isolated by implementing an interface, so in future if you decide to change implementation because of any issue, it will be not impact your framework.
And XML, Excel, text file(with any delimiter), a Database, json file are good contenders for this.
Selenium does not work with XML pages by default, as browsers do not show XML files as XML, but show its as converted to html files.
For the task I had used following code (its based on HTMLAgilityPack):
XmlActions.cs
namespace BotAgent.Ifrit.Core.Xml
{
using HtmlAgilityPack;
public partial class XmlActions
{
private HtmlDocument _xmlDoc;
private HtmlNode _rootNode;
public XmlActions()
{
_xmlDoc = new HtmlDocument();
}
private void Update()
{
string pageSource = Brwsr.CurrPage.PageSource.Replace("\r\n", string.Empty);
_xmlDoc.LoadHtml(pageSource);
_rootNode = _xmlDoc.DocumentNode;
}
public NodeSingle Elmnt(string xpath)
{
Update();
var currNode = _rootNode.SelectSingleNode(xpath);
return new NodeSingle(currNode);
}
public NodesMultiple Elmnts(string xpath)
{
Update();
var nodesGroup = _rootNode.SelectNodes(xpath);
return new NodesMultiple(nodesGroup);
}
}
}
XmlActions.NodeSingle.cs
using System;
namespace BotAgent.Ifrit.Core.Xml
{
using HtmlAgilityPack;
partial class XmlActions
{
public class NodeSingle
{
private readonly HtmlNode _currNode;
public string Text
{
get
{
return CleanUpStringFromXml(_currNode.InnerText);
}
}
public string TagName
{
get
{
return _currNode.OriginalName;
}
}
public string XmlInner
{
get
{
return _currNode.InnerHtml;
}
}
public string XmlOuter
{
get
{
return _currNode.OuterHtml;
}
}
public NodeSingle(HtmlNode currentNode)
{
_currNode = currentNode;
}
public bool Exist()
{
if (_currNode == null)
{
return false;
}
return true;
}
public bool AttributesExist()
{
return _currNode.HasAttributes;
}
public bool AttributeExist(string attributeName)
{
if (_currNode.Attributes[attributeName] != null)
{
return true;
}
return false;
}
public string AttributeValue(string attrName)
{
return _currNode.GetAttributeValue(attrName, string.Empty);
}
public bool HaveChildren()
{
var firstChildNode = _currNode.FirstChild;
if (firstChildNode != null)
{
return true;
}
return false;
}
public NodeSingle FirstChild()
{
HtmlNode node = null;
try
{
node = _currNode.ChildNodes[1];
}
catch (Exception)
{
//// No need to throw exception, its normal if there are no child
}
return new NodeSingle(node);
}
public NodeSingle Parent()
{
return new NodeSingle(_currNode.ParentNode);
}
private string CleanUpStringFromXml(string xml)
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(xml);
var root = doc.DocumentNode;
root.RemoveAllChildren();
return root.OuterHtml.Replace(" ", string.Empty);
}
}
}
}
XmlActions.NodesMultiple
namespace BotAgent.Ifrit.Core.Xml
{
using System.Collections.Generic;
using System.Linq;
using HtmlAgilityPack;
partial class XmlActions
{
public class NodesMultiple
{
private readonly HtmlNodeCollection _nodesGroup;
public int Count
{
get
{
return _nodesGroup.Count;
}
}
public NodesMultiple(HtmlNodeCollection nodesGroup)
{
this._nodesGroup = nodesGroup;
}
public NodeSingle GetElementByIndex(int index)
{
var singleNode = _nodesGroup.ElementAt(index);
return new NodeSingle(singleNode);
}
public List<NodeSingle> GetAll()
{
return _nodesGroup.Select(node => new NodeSingle(node)).ToList();
}
}
}
}
I had used my own framework code here, but this must not create problem for you to change it to clear selenium code.
After this you can create static XML var with browser instance and use like this:
bool isIdExist = Brwsr.Xml.Elem(".//div[1]").AttributeExist("id");
or
bool haveChild = Brwsr.Xml.Elem(".//div[1]").FirstChild().Exist;
I have a system that is supposed to write lines to a HTTP response stream. Each line in this system represents some kind of event, so you can see this as a notification stream. I am using .NET4 on Windows 7 using NancyFX and Nancy self hosting (0.23). The following code is functional:
using System;
using System.IO;
using System.Threading;
using Nancy;
using Nancy.Hosting.Self;
namespace TestNancy
{
public class ChunkedResponse : Response
{
public ChunkedResponse()
{
ContentType = "text/html; charset=utf-8";
Contents = stream =>
{
using (var streamWriter = new StreamWriter(stream))
{
while (true)
{
streamWriter.WriteLine("Hello");
streamWriter.Flush();
Thread.Sleep(1000);
}
}
};
}
}
public class HomeModule : NancyModule
{
public HomeModule()
{
Get["/"] = args => new ChunkedResponse();
}
}
public class Program
{
public static void Main()
{
using (var host = new NancyHost(new Uri("http://localhost:1234")))
{
host.Start();
Console.ReadLine();
}
}
}
}
Now I want to add compression to the stream to compress the amount of bandwidth. For some reason, when testing in a browser, I cannot see any result whatsoever. I have tried a lot of combinations to achieve the desired result, but this is what I have at the moment:
using System; using System.IO; using System.IO.Compression; using System.Threading; using Nancy; using Nancy.Hosting.Self;
namespace TestNancy {
public class ChunkedResponse : Response
{
public ChunkedResponse()
{
Headers["Content-Encoding"] = "gzip";
ContentType = "text/html; charset=utf-8";
Contents = stream =>
{
using (var gzip = new GZipStream(stream, CompressionMode.Compress))
using (var streamWriter = new StreamWriter(gzip))
{
while (true)
{
streamWriter.WriteLine("Hello");
streamWriter.Flush();
Thread.Sleep(1000);
}
}
};
}
}
public class HomeModule : NancyModule
{
public HomeModule()
{
Get["/"] = args => new ChunkedResponse();
}
}
public class Program
{
public static void Main()
{
using (var host = new NancyHost(new Uri("http://localhost:1234")))
{
host.Start();
Console.ReadLine();
}
}
} }
I am looking for help that either tells me what I am doing wrong concerning the HTTP protocol (e.g. I tried adding chunk lengths as described in HTTP1.1, which did not work), or help concerning Nancy where it does something I did not account for.
The problem seems to be in Gzip implementation of the framework as it never writes to output stream before getting closed,
I simply used SharpZiplib and your code seems to work for me, here is my modifications
public class ChunkedResponse : Response
{
public ChunkedResponse()
{
Headers["Transfer-Encoding"] = "chunked";
Headers["Content-Encoding"] = "gzip";
ContentType = "text/html; charset=utf-8";
Contents = stream =>
{
var gzip = new ICSharpCode.SharpZipLib.GZip.GZipOutputStream(stream);
using (var streamWriter = new StreamWriter(gzip))
{
while (true)
{
streamWriter.WriteLine("Hello");
gzip.Flush();
streamWriter.Flush();
Thread.Sleep(1000);
}
}
};
}
}
public class HomeModule : NancyModule
{
public HomeModule()
{
Get["/"] = args => new ChunkedResponse();
}
}
public class Program
{
public static void Main()
{
using (var host = new NancyHost(new HostConfiguration{AllowChunkedEncoding = true},new Uri("http://localhost:1234")))
{
host.Start();
Console.ReadLine();
}
}
}
Nuget package for SharpZipLib: PM> Install-Package SharpZipLib
It looks as though whatever calls the delegate you supply as ChunkedReponse.Contents will never return because of the while(true). Is this intended behaviour? Not knowing what this framework does with that delegate, I couldn't guess.
At first glance I did wonder whether the constructor would never return - which I guess would definitely cause a problem - but it didn't take me long to notice that it's a lambda. Fortunately.
Edit #1:
The documentation for GZipStream.Flush() says:
The current implementation of this method has no functionality.
(Overrides Stream.Flush().)
This implies to me that GZipStream doesn't write anything to the transport until it's closed. Do you experience different behaviour if you don't run the mentioned delegate forever, and instead close the stream at some point?
I have tested it myself and I think the problem is how the browser handles these chunked and compressed responses. This is what I tried and what basically worked:
Contents = stream =>
{
using (var gzip = new GZipStream(stream, CompressionMode.Compress))
using (var streamWriter = new StreamWriter(gzip))
{
for (int i = 0; i < 5;i++ )
{
string txt = "Hello";
streamWriter.WriteLine(txt);
streamWriter.Flush();
Thread.Sleep(1000);
}
}
};
The problem is that the browser waits for the chunked response to be ready before it displays the result. It probably waits with decompression until all data has been sent, although gzip supports streaming. Here is a first hint that supports my assumption.