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.
Related
I have pulled some information using newtonsoft.json and HttpClient:
public class Main {
static async Task Main() {
using(var client = new HttpClient() {
url = "webapilink goes here";
var response = await client.GetStringAsync(url);
apiStuff(the class i used to match the JSON format) variableName =
JsonConvert.DeserializeObject<apiStuff>(response);
}
}
}
I want to get the variable "variableName" to a seperate class, and for the life of me, cannot figure it out. I get an error when trying to use it anywhere outside of the HttpClient part.
As written, your async method would return void if it was not async. But it could be rewritten to return an instance of apiStuff, so that other methods (and other classes) could get that instance of apiStuff and use it:
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
public class MainClass
{
public static async Task<apiStuff> Main()
{
using (var client = new HttpClient())
{
string url = "webapilink goes here";
var response = await client.GetStringAsync(url);
apiStuff variableName =
JsonConvert.DeserializeObject<apiStuff>(response);
return variableName;
}
}
}
public class SecondClass
{
public static async Task GetApiStuff()
{
apiStuff variableName = await MainClass.Main();
// do more work with variableName
}
}
public class apiStuff { /* defined elsewhere */ }
If this wasn't what you were asking about, please clarify in the original question. (And I assume the method is not really named Main - could be confusing.)
I am working on a project to get text from this website.
But when I tested it in Visual Studio, I've got some error:
Value cannot be null. Parameter name: solutionDirectory
Here is my code:
using System;
using System.Net;
public class Program
{
public static void Main()
{
WebClient client = new WebClient();
String temp = client.DownloadString("http://www.hkex.com.hk/eng/stat/dmstat/dayrpt/hsio180629.htm");
Console.Write(temp);
}
}
Please use HttpClient Which is very good Option Compare to webClient
And your problem is sounds like your project (vcxproj) file isn't setup properly.
So create New Application Simply and run this Code.
Here you find Actually Difference
Stream client = Task.Run(()=>new HttpClient().GetAsync("http://www.hkex.com.hk/eng/stat/dmstat/dayrpt/hsio180629.htm").Result.Content.ReadAsStreamAsync()).Result;
using (var fileStream = new FileStream("D://data.txt", FileMode.Create, FileAccess.Write))
{
client.CopyTo(fileStream);
}
Full Working Code:-
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
Stream client = Task.Run(()=>new HttpClient().GetAsync("http://www.hkex.com.hk/eng/stat/dmstat/dayrpt/hsio180629.htm").Result.Content.ReadAsStreamAsync()).Result;
using (var fileStream = new FileStream("D://data.txt", FileMode.Create, FileAccess.Write))
{
client.CopyTo(fileStream);
}
}
}
}
With Await
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
data();
Console.ReadKey();
}
public static async void data()
{
var client = await new HttpClient().GetAsync("http://www.hkex.com.hk/eng/stat/dmstat/dayrpt/hsio180629.htm");
var data= await client.Content.ReadAsStreamAsync();
using (var fileStream = new FileStream("D://data.txt", FileMode.Create, FileAccess.Write))
{
data.CopyTo(fileStream);
}
}
}
}
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'm working on an iOS application using Xamarin.iOS / MonoTouch and I've run across a bit of a dilemma. We're downloading quite a bit of data with our application by querying JSON-files which are then processed into models that are saved into our local sqlite-database. The problem is that the class I've written is made for specific types, and I want to be able to use the same class for fetching all JSON data into local objects.
Here is my code:
using System;
using System.IO;
using System.Net;
using Newtonsoft.Json;
using System.Collections.Generic;
#pragma warning disable 0414 // Supressing Warning CS0414:
namespace CommonLibrary {
public class JSONHandler {
// Debug Constants:
private static String DEBUG_FILE_TAG = "[JSONHandler] ";
// Define variables:
private Uri JSONRequestURL;
private bool RequestTimedOut;
private bool RequestSuccessful;
private string ResponseContent;
private List<Post> JSONObjects;
// Define objects:
private HttpWebRequest JSONWebRequest;
private HttpWebResponse JSONWebResponse;
// Constructor:
public JSONHandler(string requestURL){
// Set request URL:
this.JSONRequestURL = new Uri(requestURL);
// Set default statuses:
this.RequestTimedOut = false;
this.RequestSuccessful = false;
}
// Create web request:
private void CreateWebRequest(){
this.JSONWebRequest = (HttpWebRequest) WebRequest.Create (this.JSONRequestURL);
this.JSONWebRequest.Method = "GET";
this.JSONWebRequest.Timeout = 5000;
this.JSONWebRequest.KeepAlive = false;
this.JSONWebRequest.AllowAutoRedirect = false;
this.JSONWebRequest.ContentType = "application/json";
}
// Get request response:
private void GetRequestResponse(){
try {
// Catch the response:
this.JSONWebResponse = (HttpWebResponse) this.JSONWebRequest.GetResponse ();
// Check the status code:
if (this.JSONWebResponse.StatusCode == HttpStatusCode.OK){
// Get content:
StreamReader reader = new StreamReader (this.JSONWebResponse.GetResponseStream ());
this.ResponseContent = reader.ReadToEnd();
// Close response:
this.JSONWebResponse.Close();
// Check response length:
if (!String.IsNullOrWhiteSpace(this.ResponseContent)){
this.JSONObjects = JsonConvert.DeserializeObject<List<Post>>(this.ResponseContent);
this.RequestSuccessful = true;
} else {
this.RequestSuccessful = false;
}
} else {
this.RequestSuccessful = false;
}
} catch (WebException){
this.RequestTimedOut = true;
this.RequestSuccessful = false;
} catch (TimeoutException){
this.RequestTimedOut = true;
this.RequestSuccessful = false;
}
}
// Fetch JSON from server:
public void FetchJSON(){
this.CreateWebRequest ();
this.GetRequestResponse ();
}
// Return request status:
public bool RequestWasSuccessful(){
return RequestSuccessful;
}
// Return timeout status:
public bool RequestDidTimeOut(){
return RequestTimedOut;
}
// Get object count:
public int GetJSONCount(){
return this.JSONObjects.Count;
}
// Get list of objects:
public List<Post> GetJSONObjects (){
return this.JSONObjects;
}
}
}
As you can see, I have to change the type that are stored in the lists from Post to any other object and create a new file, for instance, JSONPost, JSONRunner, JSONLayer etc, and I'd like to handle that with just one class, JSONHandler. Hopefully someone here can help me with this matter. I'm going to have the following classes now:
Post
Layer
RelayTeam
RelayRunner
RelayRunnerResult
MarathonRunner
MarathonRunnerResult
And as you all can understand it won't be good having a duplicated file just for all of these.
I'm really thankful for any help I can get!
Best regards,
Jonathan
Use Generics - if the type of the JSONObjects collection is the only thing that varies, you can do this
public class JSONHandler<T> {
...
private List<T> JSONObjects;
When you create a new JSONHandler instance, you can specify the type
var handler = new JSONHandler<Post>();
var handler = new JSONHandler<Layer>();
var handler = new JSONHandler<RelayTeam>();
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...