Error creating Uri in C# Monodevelop - c#

I'm trying to do a desktop application which communicates with an API REST, then I decided to do it with MonoDevelop in my xubuntu. I tried to Create a Uri from string with the constructor but, when the object Uri is created, it appears in my MonoDevelop debugger:
stationUri {System.Uri}
System.Uri AbsolutePath System.NullReferenceException: Object
reference not set to an instance of an object AbsoluteUri
System.NullReferenceException: Object reference not set to an
instance of an object Authority System.NullReferenceException:
Object reference not set to an instance of an object DnsSafeHost
System.NullReferenceException: Object reference not set to an
instance of an object Fragment System.NullReferenceException:
Object reference not set to an instance of an object Host
System.NullReferenceException: Object reference not set to an
instance of an object HostNameType System.NullReferenceException:
Object reference not set to an instance of an object
urlConParametros https://api.thingspeak.com/channels/***/fields/4.json?api_key=***&results=2 string
Because of security reasons I didn't show the full URL.
And the respective code associated with this error:
public string GetResponse_GET(string url, Dictionary<string, string> parameters)
{
try
{
//Concatenamos los parametros, OJO: antes del primero debe estar el caracter "?"
string parametrosConcatenados = ConcatParams(parameters);
string urlConParametros = url + "?" + parametrosConcatenados;
string responseFromServer = null;
Uri stationUri = new Uri(urlConParametros);
if(!stationUri.IsWellFormedOriginalString())
{
System.Console.WriteLine("Url VacĂ­a");
}
else
{
System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(stationUri);
wr.Method = "GET";
wr.ContentType = "application/x-www-form-urlencoded";
System.IO.Stream newStream;
// Obtiene la respuesta
System.Net.WebResponse response = wr.GetResponse();
// Stream con el contenido recibido del servidor
newStream = response.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(newStream);
// Leemos el contenido
responseFromServer = reader.ReadToEnd();
// Cerramos los streams
reader.Close();
newStream.Close();
response.Close();
}
return responseFromServer;
}
catch (System.Web.HttpException ex)
{
if (ex.ErrorCode == 404)
throw new Exception("Servicio Remoto No Encontrado: " + url);
else throw ex;
}
}
private string ConcatParams(Dictionary<string, string> parameters)
{
bool FirstParam = true;
string Parametros = null;
if (parameters != null)
{
Parametros = "";
foreach (KeyValuePair<string, string> param in parameters)
{
if(!FirstParam)
Parametros+="&";
Parametros+= param.Key + "=" + param.Value;
FirstParam = false;
}
}
return Parametros == null ? String.Empty : Parametros.ToString();
}
If I run completely the code, throws the next stackTrace associated (I removed the sensitive data):
Exception in Gtk# callback delegate
Note: Applications can use GLib.ExceptionManager.UnhandledException to handle the exception.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object
at System.Net.WebRequest.Create (System.Uri requestUri) [0x00000] in :0
at MainWindow.GetResponse_GET (System.String url, System.Collections.Generic.Dictionary`2 parameters) [0x0002b] in /home//MonoDevelop Projects///MainWindow.cs:92
at MainWindow.showAct (System.Object sender, System.EventArgs e) [0x0003f] in /home//MonoDevelop Projects///MainWindow.cs:34
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in :0
--- End of inner exception stack trace ---
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00053] in :0
at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in :0
at System.Delegate.DynamicInvokeImpl (System.Object[] args) [0x0010d] in :0
at System.MulticastDelegate.DynamicInvokeImpl (System.Object[] args) [0x0000b] in :0
at System.Delegate.DynamicInvoke (System.Object[] args) [0x00000] in :0
at GLib.Signal.ClosureInvokedCB (System.Object o, GLib.ClosureInvokedArgs args) [0x00067] in :0
at GLib.SignalClosure.Invoke (GLib.ClosureInvokedArgs args) [0x0000c] in :0
at GLib.SignalClosure.MarshalCallback (IntPtr raw_closure, IntPtr return_val, UInt32 n_param_vals, IntPtr param_values, IntPtr invocation_hint, IntPtr marshal_data) [0x00086] in :0
at GLib.ExceptionManager.RaiseUnhandledException (System.Exception e, Boolean is_terminal) [0x00000] in :0
at GLib.SignalClosure.MarshalCallback (IntPtr raw_closure, IntPtr return_val, UInt32 n_param_vals, IntPtr param_values, IntPtr invocation_hint, IntPtr marshal_data) [0x00000] in :0
at Gtk.Application.gtk_main () [0x00000] in :0
at Gtk.Application.Run () [0x00000] in :0
at .MainClass.Main (System.String[] args) [0x00012] in /home//MonoDevelop Projects///Program.cs:13
I don't know why can't establish correctly the Uri from string... Then if I pass the incorrect Uri to create the WebRequest throws an error too...
Does anyone know what I am doing wrong here.

Thank you so much for the help, I solved it copying cs files and creating an empty proyect C# in monodevelop and putting the old files in the new project and reloading references, then new Uri(string) works... Before I created the project as gtk#2.0 and now like empty and works... I dnt know the reason...

check to make sure that query string does not contain any characters that are not url friendly otherwise you need to url encode it. To avoid having to encode it yourself you can use the UriBuilder class when contructing the url
var uriBuilder = new UriBuilder(uri);
uriBuilder.Query = ConcatParams(parameters);
Uri stationUri = uriBuilder.Uri;
//if NOT well formed
if(!stationUri.IsWellFormedOriginalString()) { //Note the `!` exclamation mark
//...code removed for brevity
} else {
//...code removed for brevity
}
It will url encode any values as necessary.

Related

Returning SpreadsheetGear workbook stream from WebMethod

I would like to provide a web service that lets me download certain Excel workbooks. These Excel workbooks are SpreadsheetGear objects that may be modified with data. I don't want to write them as a file and return the file. Instead, I'd like to stream them into the browser so the user gets a downloaded file.
Here is my attempt that does not work, drawn from this guide from SpreadsheetGear's site:
[System.Web.Services.WebMethod(
Description = "Returns a stream for the excel file")]
public ActionResult downloadTemplate(string excelFileName)
{
var workbook = makeSpreadsheetGearWorkbookFrom(excelFileName);
// Save workbook to an Open XML (XLSX) workbook stream.
System.IO.Stream stream = workbook.SaveToStream(
SpreadsheetGear.FileFormat.OpenXMLWorkbook);
// Reset stream's current position back to the beginning.
stream.Seek(0, System.IO.SeekOrigin.Begin);
return new FileStreamResult(stream,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
I get the following error:
The web service returned the following result:
500 - Internal Server Error
System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: System.Web.Mvc.FileStreamResult cannot be serialized because it does not have a parameterless constructor.
at System.Xml.Serialization.TypeDesc.CheckSupported () [0x0001c] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.TypeScope.GetTypeDesc (System.Type type, System.Reflection.MemberInfo source, System.Boolean directReference, System.Boolean throwOnError) [0x0006a] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.TypeScope.GetTypeDesc (System.Type type) [0x00000] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.XmlSerializationWriter.CreateUnknownTypeException (System.Type type) [0x00039] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.XmlSerializationWriter.CreateUnknownTypeException (System.Object o) [0x00007] in <611e64636ff745389933c69c817b2d4a>:0
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write3_ActionResult (System.String n, System.String ns, System.Web.Mvc.ActionResult o, System.Boolean isNullable, System.Boolean needType) [0x00048] in <3fa7e61a58e74ec08df7a46ab2fb8972>:0
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write7_ActionResult (System.Object o) [0x00028] in <3fa7e61a58e74ec08df7a46ab2fb8972>:0
at Microsoft.Xml.Serialization.GeneratedAssembly.ActionResultSerializer.Serialize (System.Object objectToSerialize, System.Xml.Serialization.XmlSerializationWriter writer) [0x00000] in <3fa7e61a58e74ec08df7a46ab2fb8972>:0
at System.Xml.Serialization.XmlSerializer.Serialize (System.Xml.XmlWriter xmlWriter, System.Object o, System.Xml.Serialization.XmlSerializerNamespaces namespaces, System.String encodingStyle, System.String id) [0x00098] in <611e64636ff745389933c69c817b2d4a>:0
StackTraceEnd
at System.Xml.Serialization.XmlSerializer.Serialize (System.Xml.XmlWriter xmlWriter, System.Object o, System.Xml.Serialization.XmlSerializerNamespaces namespaces, System.String encodingStyle, System.String id) [0x0012f] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.XmlSerializer.Serialize (System.Xml.XmlWriter xmlWriter, System.Object o, System.Xml.Serialization.XmlSerializerNamespaces namespaces, System.String encodingStyle) [0x00000] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.XmlSerializer.Serialize (System.Xml.XmlWriter xmlWriter, System.Object o, System.Xml.Serialization.XmlSerializerNamespaces namespaces) [0x00000] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.XmlSerializer.Serialize (System.IO.TextWriter textWriter, System.Object o, System.Xml.Serialization.XmlSerializerNamespaces namespaces) [0x00015] in <611e64636ff745389933c69c817b2d4a>:0
at System.Xml.Serialization.XmlSerializer.Serialize (System.IO.TextWriter textWriter, System.Object o) [0x00000] in <611e64636ff745389933c69c817b2d4a>:0
at System.Web.Services.Protocols.XmlReturnWriter.Write (System.Web.HttpResponse response, System.IO.Stream outputStream, System.Object returnValue) [0x00079] in <11189ae945ae429a8c10c5e8a65a097a>:0
at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns (System.Object[] returnValues, System.IO.Stream outputStream) [0x0003f] in <11189ae945ae429a8c10c5e8a65a097a>:0
at System.Web.Services.Protocols.WebServiceHandler.WriteReturns (System.Object[] returnValues) [0x00051] in <11189ae945ae429a8c10c5e8a65a097a>:0
at System.Web.Services.Protocols.WebServiceHandler.Invoke () [0x000cc] in <11189ae945ae429a8c10c5e8a65a097a>:0
How should I approach this?
Solved the problem by returning a list of bytes instead of a StreamResult, like so:
public byte[] downloadTemplate(string excelFileName)
//...
byte[] modelData = toByteArray(stream);
return modelData;
}
public byte[] toByteArray(System.IO.Stream stream)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
stream.CopyTo(ms);
return ms.ToArray();
}
}
It is easy to put the byte array into a JObject and then into an XML Envelope.

Sqlite throws NullReferenceException

From this code a Null exception is throw and I'm pusled as to why that is. The line that throws the NullReferenceException is this one,
if (await dbConn.FindAsync<ShoppingList>(x => x.Name == insertedList.Name) != null)
Here is the whole method:
public async Task<string> SaveSingleShoppingList(IShoppingList shoppingList)
{
try
{
var dbConn = new SQLiteAsyncConnection(dbPath);
ShoppingList insertedList = (ShoppingList)shoppingList;
await SaveGroceries(shoppingList.Groceries, shoppingList.Name, dbConn);
if(await dbConn.FindAsync<ShoppingList>(x => x.Name == insertedList.Name) != null)
await dbConn.UpdateAsync(insertedList);
else
await dbConn.InsertAsync(insertedList);
return "Shopping list Saved!";
}
catch (SQLiteException ex)
{
return ex.Message;
}
catch(NullReferenceException nre)
{
return nre.Message;
}
}
Below is the full extent of the exception message
{System.NullReferenceException: Object reference not set to an
instance of an object at
SQLite.TableQuery1[ShoppingAssistant.ShoppingList].CompileExpr
(System.Linq.Expressions.Expression expr,
System.Collections.Generic.List1 queryArgs) [0x00000] in :0
at SQLite.TableQuery1[ShoppingAssistant.ShoppingList].CompileExpr
(System.Linq.Expressions.Expression expr,
System.Collections.Generic.List1 queryArgs) [0x00000] in :0
at
SQLite.TableQuery1[ShoppingAssistant.ShoppingList].GenerateCommand
(System.String selectionList) [0x00000] in <filename unknown>:0 at
SQLite.TableQuery1[ShoppingAssistant.ShoppingList].GetEnumerator ()
[0x00000] in :0
at
System.Collections.Generic.List1[ShoppingAssistant.ShoppingList].AddEnumerable
(IEnumerable1 enumerable) [0x00000] in :0
at
System.Collections.Generic.List1[ShoppingAssistant.ShoppingList]..ctor
(IEnumerable1 collection) [0x00000] in :0
at System.Linq.Enumerable.ToList[ShoppingList] (IEnumerable`1
source) [0x00000] in :0
at
SQLite.TableQuery`1[ShoppingAssistant.ShoppingList].FirstOrDefault ()
[0x00000] in :0
at SQLite.SQLiteConnection.Find[ShoppingList]
(System.Linq.Expressions.Expression`1 predicate) [0x00000] in
:0
at
SQLite.SQLiteAsyncConnection+c__AnonStorey7`1[ShoppingAssistant.ShoppingList].<>m__0
() [0x00000] in :0
at
System.Threading.Tasks.TaskActionInvoker+FuncInvoke`1[ShoppingAssistant.ShoppingList].Invoke
(System.Threading.Tasks.Task owner, System.Object state,
System.Threading.Tasks.Task context) [0x00000] in :0
at System.Threading.Tasks.Task.InnerInvoke () [0x00000] in :0 at System.Threading.Tasks.Task.ThreadStart () [0x00000]
in :0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()
[0x00000] in :0 at
System.Runtime.CompilerServices.TaskAwaiter`1[ShoppingAssistant.ShoppingList].GetResult
() [0x00000] in :0 at
ShoppingAssistant.SQLiteDataAcces+d__2d.MoveNext
() [0x0009d] in
c:\Users\kaj\Desktop\dbTest\dbTest\SQLiteDataAcces.cs:187
} System.NullReferenceException

System.Reflection.TargetInvocationException thrown when trying to instantiate new ViewController

I have a storyboard. Because I load a view in code (depending on conditions) I haven't used the segue anymore. Now I want to load another view but I'm getting the following error:
System.Reflection.TargetInvocationException was thrown
Exception has been thrown by the target of an invocation.
ListButton.TouchUpInside += (object sender, EventArgs e) => {
MyListController myListController = this.Storyboard.InstantiateViewController ("MyListController") as MyListController;
myListController.EdgesForExtendedLayout = UIRectEdge.None;
if (myListController != null) {
this.NavigationController.PushViewController (myListController, true);
}
};
When the button (ListButton) is pressed the view should be loaded onto the navigation stack. The error occurs with InstantiateViewController.
How can I solve that?
Edit:
I went into MyListController and if I comment the following out the view gets loaded:
public MyListController (IntPtr handle) : base (handle)
{
TableView.RegisterClassForCellReuse (typeof(UITableViewCell), listCellId);
TableView.Source = new MyListDataSource (this);
MyList = new List<string> ();
}
Log:
System.Reflection.TargetInvocationException: Exception has been thrown
by the target of an invocation. ---> System.Exception: Object
reference not set to an instance of an object at
TestApp.MyListController.ViewDidLoad () [0x0004c] in
/Users/xxx/Projects/TestApp/TestApp/TestApp/MyListController.cs:78
at at (wrapper managed-to-native)
MonoTouch.ObjCRuntime.Messaging:IntPtr_objc_msgSendSuper
(intptr,intptr) at
MonoTouch.UIKit.UITableViewController.get_TableView () [0x00000] in
:0 at TestApp.MyListController..ctor (IntPtr
handle) [0x00009] in
/Users/xxx/Projects/TestApp/TestApp/TestApp/MyListController.cs:17
at at (wrapper managed-to-native)
System.Reflection.MonoCMethod:InternalInvoke
(System.Reflection.MonoCMethod,object,object[],System.Exception&) at
System.Reflection.MonoCMethod.InternalInvoke (System.Object obj,
System.Object[] parameters) [0x00002] in
/Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:537
--- End of inner exception stack trace --- at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj,
System.Object[] parameters) [0x00016] in
/Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:543
at System.Reflection.MonoCMethod.DoInvoke (System.Object obj,
BindingFlags invokeAttr, System.Reflection.Binder binder,
System.Object[] parameters, System.Globalization.CultureInfo culture)
[0x00095] in
/Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:528
at System.Reflection.MonoCMethod.Invoke (BindingFlags invokeAttr,
System.Reflection.Binder binder, System.Object[] parameters,
System.Globalization.CultureInfo culture) [0x00000] in
/Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:556
at System.Reflection.ConstructorInfo.Invoke (System.Object[]
parameters) [0x00000] in
/Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/ConstructorInfo.cs:62
at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject[NSObject] (IntPtr
ptr, System.Type type, MissingCtorResolution missingCtorResolution)
[0x00000] in :0 at
MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr
klass, MissingCtorResolution missingCtorResolution) [0x00000] in
:0 at MonoTouch.ObjCRuntime.Runtime.GetNSObject
(IntPtr ptr, MissingCtorResolution missingCtorResolution) [0x00000] in
:0 at MonoTouch.ObjCRuntime.Runtime.GetNSObject
(IntPtr ptr) [0x00000] in :0 at
MonoTouch.UIKit.UIStoryboard.InstantiateViewController (System.String
identifier) [0x00000] in :0 at
TestApp.StartScreenViewController.m__1 (System.Object
sender, System.EventArgs e) [0x0000c] in
/Users/xxx/Projects/TestApp/TestApp/TestApp/StartScreenViewController.cs:57
at MonoTouch.UIKit.UIControlEventProxy.Activated () [0x00000] in
:0 at at (wrapper managed-to-native)
MonoTouch.UIKit.UIApplication:UIApplicationMain
(int,string[],intptr,intptr) at MonoTouch.UIKit.UIApplication.Main
(System.String[] args, System.String principalClassName, System.String
delegateClassName) [0x00000] in :0 at
TestApp.Application.Main (System.String[] args) [0x00008] in
/Users/xxx/Projects/TestApp/TestApp/TestApp/Main.cs:17
Try:
Hmm, now I added a new UITableViewController to the storyboard, changed some classes to public, changed variable names to starting with lower case. Also the old UITableviewController had a problem with an added SearchController. Now I made everything new and the problem only relied in the viewDidLoad but that was not the original problem. It was one of these steps (perhaps the SearchController problem).
Problematic Code:
this.NavigationController.ToolbarHidden = false;
It seems that he can't find the NavigationController ... How do I addd the navigation controller to the new created view?

How to backup PostgreSql database from browser in MVC2 application on Mono

Mono MVC2 application is used to backup PostgreSql database from browser.
After some time of work exception Thread was being aborted occurs (whole error message is below).
pg_dump runs but looks like it is aborted. apache error_log contains its output ending in middle of line.
How to create backup copy from PostgreSql database which copy can saved from browser over internet ?
Using mod_mono with Apache
Andrus.
[Authorize]
public class BackupController : ControllerBase
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Backup()
{
var pinfo = new ProcessStartInfo();
var fn = "backup.backup";
pinfo.Arguments = " -ib -Z6 -f \"" + fn + "\" -Fc -h \"" + "myserver" + "\" -U \"" +
"postgres" + " \"" + "mydb" + "\"";
pinfo.FileName = "/usr/bin/pg_dump";
pinfo.UseShellExecute = false;
using (var process = new Process())
{
process.EnableRaisingEvents = true;
process.StartInfo = pinfo;
process.Start();
while (!process.HasExited)
Thread.Sleep(2000);
process.WaitForExit();
if (process.ExitCode!=0)
throw new Exception("error");
process.Close();
}
Response.ClearContent();
Response.WriteFile(fn);
Response.End();
System.IO.File.Delete(fn);
return null;
}
}
result:
Server Error in '/myapp' Application
--------------------------------------------------------------------------------
Thread was being aborted
Description: HTTP 500. Error processing request.
Stack Trace:
System.Threading.ThreadAbortException: Thread was being aborted
at System.Web.HttpApplication.async_handler_complete_cb (IAsyncResult ar) [0x0002d] in /usr/src/redhat/BUILD/mono-2.10.2/mcs/class/System.Web/System.Web/HttpApplication.cs:1010
at System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncResult`1[System.Web.Mvc.Async.AsyncVoid].Begin (System.AsyncCallback callback, System.Object state, Int32 timeout) [0x00000] in <filename unknown>:0
at System.Web.Mvc.Async.AsyncResultWrapper.BeginSynchronous[AsyncVoid] (System.AsyncCallback callback, System.Object state, System.Func`1 func, System.Object tag) [0x00000] in <filename unknown>:0
at System.Web.Mvc.Async.AsyncResultWrapper.BeginSynchronous (System.AsyncCallback callback, System.Object state, System.Action action, System.Object tag) [0x00000] in <filename unknown>:0
at System.Web.Mvc.MvcHandler.BeginProcessRequest (System.Web.HttpContextBase httpContext, System.AsyncCallback callback, System.Object state) [0x00000] in <filename unknown>:0
at System.Web.Mvc.MvcHandler.BeginProcessRequest (System.Web.HttpContext httpContext, System.AsyncCallback callback, System.Object state) [0x00000] in <filename unknown>:0
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest (System.Web.HttpContext context, System.AsyncCallback cb, System.Object extraData) [0x00000] in <filename unknown>:0
at System.Web.HttpApplication+<Pipeline>c__Iterator6.MoveNext () [0x00d42] in /usr/src/redhat/BUILD/mono-2.10.2/mcs/class/System.Web/System.Web/HttpApplication.cs:1365
at System.Web.HttpApplication.Tick () [0x00000] in /usr/src/redhat/BUILD/mono-2.10.2/mcs/class/System.Web/System.Web/HttpApplication.cs:932
--------------------------------------------------------------------------------
Version information: Mono Runtime Version: 2.10.2 (tarball Mon Apr 18 18:57:39 UTC 2011); ASP.NET Version: 2.0.50727.1433

How can I correctly use Mono.Unix.UnixPipes.CreatePipes?

I want to communicate with a subprocess using a pipe other than stdin, stdout and stderr. I'm trying to use Mono.Unix.UnixPipes.CreatePipes for this. However, I can't find any examples and my best guess of how to use it isn't working. It seems that the child process I create with Process.Start cannot write to the inherited file handle. I am wondering if perhaps it has not actually inherited the handle at all. Here's my (reduced) code:
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Collections.Generic;
using Mono.Unix;
class Program
{
static void Main(string[] args)
{
if (args.Length==0)
{
InvokeChildProcess(args);
}
else
{
RunAsChildProcess(args);
}
}
static int InvokeChildProcess(string[] aArgs)
{
var childToParentPipe = Mono.Unix.UnixPipes.CreatePipes();
var childToParentStream = childToParentPipe.Reading;
string childHandle = childToParentPipe.Writing.Handle.ToString();
var startInfo = new ProcessStartInfo(
System.Reflection.Assembly.GetExecutingAssembly().Location,
childHandle)
{
UseShellExecute = false,
};
Process childProcess = Process.Start(startInfo);
childToParentPipe.Writing.Close();
using (var reader = new StreamReader(childToParentStream))
{
Console.WriteLine("[PARENT] Waiting for child output...");
string output = reader.ReadToEnd();
Console.Write("[PARENT] Received output ({0} chars): ", output.Length);
Console.WriteLine(output);
Console.WriteLine("[PARENT] Waiting for child to exit...");
childProcess.WaitForExit();
Console.WriteLine("[PARENT] Saw child exit with code {0}.", childProcess.ExitCode);
return childProcess.ExitCode;
}
}
static void RunAsChildProcess(string[] args)
{
int handle=int.Parse(args[0]);
Console.WriteLine("[CHILD] Writing to file handle {0}.", handle);
var pipeToParent = new Mono.Unix.UnixStream(handle);
Thread.Sleep(2000);
using (var writer = new StreamWriter(pipeToParent))
{
writer.WriteLine("Message from child.");
writer.Flush();
Environment.Exit(123);
}
}
}
Here's the output when it runs:
weeble#weeble-vm-oneiric32:~/dev$ mono MinimalPipeTest.exe
[PARENT] Waiting for child output...
[PARENT] Received output (0 chars):
[PARENT] Waiting for child to exit...
[CHILD] Writing to file handle 4.
Unhandled Exception: System.ArgumentException: Can not write to stream
at System.IO.StreamWriter..ctor (System.IO.Stream stream, System.Text.Encoding encoding, Int32 bufferSize) [0x00000] in <filename unknown>:0
at System.IO.StreamWriter..ctor (System.IO.Stream stream) [0x00000] in <filename unknown>:0
at (wrapper remoting-invoke-with-check) System.IO.StreamWriter:.ctor (System.IO.Stream)
at Program.RunAsChildProcess (System.String[] args) [0x00000] in <filename unknown>:0
at Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: Can not write to stream
at System.IO.StreamWriter..ctor (System.IO.Stream stream, System.Text.Encoding encoding, Int32 bufferSize) [0x00000] in <filename unknown>:0
at System.IO.StreamWriter..ctor (System.IO.Stream stream) [0x00000] in <filename unknown>:0
at (wrapper remoting-invoke-with-check) System.IO.StreamWriter:.ctor (System.IO.Stream)
at Program.RunAsChildProcess (System.String[] args) [0x00000] in <filename unknown>:0
at Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
[PARENT] Saw child exit with code 1.
weeble#weeble-vm-oneiric32:~/dev$
This example was compiled and run with Mono 2.10 as distributed in Ubuntu Oneiric.
What am I doing wrong? How can I ensure that the child process will be able to write to the pipe?
EDIT - It looks like Process.Start does indeed close all file descriptors in the child process except for 0, 1 and 2. See here in CreateProcess:
https://github.com/mono/mono/blob/master/mono/io-layer/processes.c#L988
for (i = getdtablesize () - 1; i > 2; i--) {
close (i);
}
I guess that means I can't use UnixPipes and Process.Start. Is there another way?
As I understand it, you cannot use a pipe bi-directionally here. In other words, you cannot read and write with the same pipe. You need two.

Categories

Resources