Alternative for Marshal.GetExceptionCode()? - c#

Marshal.GetExceptionCode() has been obsoleted, and the message does not suggest a way forward.
at the moment I use this in the following opensource project:
https://github.com/dbones-labs/auditable/blob/master/src/Auditable/AuditableContext.cs#L143
the idea is, if the client code/app within a using block throws an exception it should not write a log.
However, the project code only has a using statement to figure out if it should react or not.
what is the alternative to this? (without changeing the API for the calling code)
example use of the API
https://dbones-labs.github.io/auditable/quick-examples/aspnet-example.html#3-add-some-auditable-logs

From a quick test it seems you can use Marshal.GetExceptionPointers():
public class MyDisposable : IDisposable
{
public void Dispose()
{
var ptr = Marshal.GetExceptionPointers();
Console.WriteLine(ptr);
}
}
try
{
using (new MyDisposable())
{
}
using (new MyDisposable())
{
throw new Exception();
}
}
catch (Exception)
{
}
using (new MyDisposable())
{
}
It is non-zero if there is an Exception "in the air".
Note that Marshal.GetExceptionPointers() was always present in .NET Framework but was reintroduced in .NET Core only >= 3.0. So for .NET Core 1.0-2.2 you'll need to use Marshal.GetExceptionCode()`.

Related

Applying custom request options for a remote SPARQL connector in dotNetRdf

I'm trying to add custom headers to the HTTP requsets a SPARQL endpoint connector issues. The connector can use a custom remote endpoint, which inherits an ApplyCustomRequestOptions method I can override. Documentation for that method says
[...] add any additional custom request options/headers to the request.
However my overridden method is never called (so my custom options are not applied, so I can't add the headers).
The following code works as expected, except that my ApplyCustomRequestOptions is never invoked:
using System;
using System.Net;
using VDS.RDF.Query;
using VDS.RDF.Storage;
class Program
{
static void Main(string[] args)
{
var endpointUri = new Uri("https://query.wikidata.org/sparql");
var endpoint = new CustomEndpoint(endpointUri);
using (var connector = new SparqlConnector(endpoint))
{
var result = connector.Query("SELECT * WHERE {?s ?p ?o} LIMIT 1");
}
}
}
public class CustomEndpoint : SparqlRemoteEndpoint
{
public CustomEndpoint(Uri endpointUri) : base(endpointUri) { }
protected override void ApplyCustomRequestOptions(HttpWebRequest httpRequest)
{
// This is never executed.
base.ApplyCustomRequestOptions(httpRequest);
// Implementation omitted.
}
}
Is this the correct way to use these methods? If it isn't, what is it?
BTW this is dotNetRdf 1.0.12, .NET 4.6.1. I've tried multiple SPARQL endpoints, multiple queries (SELECT & CONSTRUCT) and multiple invocations of SparqlConnector.Query.
This is a bug. I've found the problem and fixed it and submitted a PR. You can track the status of the issue here: https://github.com/dotnetrdf/dotnetrdf/issues/103

System.AccessViolationException in C# interface to Swi-prolog

I am new here and I hope that i will find a solution for my problem. The background of the problem is as follows:
I am trying to build an expert system that constitute a C# front-end which is interacting with Swi-prolog.
I have downloaded SwiPlCs.dll (A CSharp class library to connect .NET languages with Swi-Prolog)
And added a reference to it in a Visual Studio project(Win form app) that I have created to test if I can query prolog from c# (I followed the example used in the documentation found here).
It worked fine.
Then, in a more complicated scenario, I have built a WCF service that will act as an intermediary layer between Swi-Prolog and C# client application (it consumes the service).
The service is hosted in IIS 7.0.
For the sake of simplicity, lets say my service contains three methods.
The first method initializes the prolog engine, consults prolog source file then queries the file.
The second method performs another query.
The third method calls PlCleanup().
Method#1:
public void LaunchAssessment()
{
Dictionary<string, string> questions = new Dictionary<string, string>();
#region : Querying prolog using SwiPlCs
try
{
if (!PlEngine.IsInitialized)
{
String[] param = { "-q" };
PlEngine.Initialize(param);
PlQuery.PlCall("consult('D:/My FYP Work/initialAssessment')");
using (var q = new PlQuery("go(X, Y)"))
{
foreach (PlQueryVariables v in q.SolutionVariables)
{
questions.Add("name", v["X"].ToString());
questions.Add("age", v["Y"].ToString());
}
}
}
}
catch (SbsSW.SwiPlCs.Exceptions.PlException exp)
{
throw new FaultException<PrologFault>(new PrologFault(exp.Source), exp.MessagePl);
}
#endregion
Callback.PoseQuestion(questions, ResponseType.None);
}
Method#2:
public void DetermineAgeGroup(int age)
{
//Determine age group
string age_group = string.Empty;
try
{
using (var query = new PlQuery("age_group(" + age + ", G)"))
{
foreach (PlQueryVariables v in query.SolutionVariables)
age_group += v["G"].ToString();
}
}
catch (SbsSW.SwiPlCs.Exceptions.PlException exp)
{
throw new FaultException<PrologFault>(new PrologFault(exp.Source), exp.MessagePl);
}
//Check whether age_group is found or not
if (string.IsNullOrEmpty(age_group))
{
throw new FaultException<NoSolutionFoundFault>(new NoSolutionFoundFault("No solution found"), "Age specified exceeds the diagnosis range!");
}
else
{
Callback.RespondToUser(age_group, ResponseType.Age);
}
}
Method#3:
public void QuitProlog()
{
if (PlEngine.IsInitialized)
{
PlEngine.PlCleanup();
}
}
The client invokes the first method just fine and a result of the first query is successfully returned. When client tries to call the second method an exception is thrown with message (attempted to read or write protected memory) which causes the application to freeze. I checked the event viewer and this is what I get:
Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
Stack:
at SbsSW.SwiPlCs.SafeNativeMethods.PL_new_term_ref()
at SbsSW.SwiPlCs.PlQuery..ctor(System.String, System.String)
at SbsSW.SwiPlCs.PlQuery..ctor(System.String)
at PrologQueryService.PrologQueryService.DetermineAgeGroup(Int32)
I also tried to use the interface for a .NET project.
Looking in the official repository of the CSharp interface to SWI-Prolog I noticed that the project is very old and the latest updates do not seem included in the binaries available in the download page of the official website.
Then I did the following steps:
The contrib repository dedicated to .NET indicates that the compatible SWI-Prolog version (at the time of writing) is "8.0.3-1" (look in the README file).
-> Then I uninstalled from my computer the latest stable and installed the indicated one. I got it from the full list of downloads of the old versions at this link.
I cloned the SWI-Prolog/contrib-swiplcs repository, unloaded the incompatible projects from the solution, in my case, since I don't use Visual Studio.
-> I set the target framework to Net Framework 4.8 and recompiled it (you can also do this with standard NET). Beware of some pragma directives defined in the old project file (For example I re-defined _PL_X64 variable via code.
I brought the main unit test methods into a new project with xUnit wiht the appropriate changes.
I set the target to x64, recompiled and rebuilt the tests and the "hello world" example.
It worked!
I was able to use SWI-Prolog both for Net 4.8 and in other Net Core applications (if you make the needed changes in order to target the Net Standard). You should not have any problem in both cases).
This is my fork as a preliminary example.
Finally, I can load a *.pl Prolog file with a program in my C# application and use it to evaluate some business logic rules (example with boolean answer [Permitted/Not-Permitted]):
[Fact]
public void ShouldLoadAProgramAndUseIt()
{
var pathValues = Environment.GetEnvironmentVariable("PATH");
pathValues += #";C:\Program Files\swipl\bin";
Environment.SetEnvironmentVariable("PATH", pathValues);
// Positioning to project folder
var currentDirectory = Directory.GetCurrentDirectory().Split('\\').ToList();
currentDirectory.RemoveAll(r => currentDirectory.ToArray().Reverse().Take(3).Contains(r));
var basePath = currentDirectory.Aggregate((c1, c2) => $"{c1}\\{c2}");
var filePath = $"{basePath}\\prolog_examples\\exec_checker.pl";
String[] param = { "-q", "-f", filePath };
PlEngine.Initialize(param);
try
{
var query = "exutable('2020-08-15',[('monthly', ['2019-12-30', '2020-03-10'])])";
_testOutputHelper.WriteLine($"Query: {query}");
using (var q = new PlQuery(query))
{
var booleanAnswer = q.NextSolution();
_testOutputHelper.WriteLine($"Answer: {booleanAnswer}");
Assert.True(booleanAnswer);
}
query = "exutable('2020-08-15',[('daily', ['2019-12-30', '2020-08-15'])])";
_testOutputHelper.WriteLine($"Query: {query}");
using (var q = new PlQuery(query))
{
var booleanAnswer = q.NextSolution();
_testOutputHelper.WriteLine($"Answer: {booleanAnswer}");
Assert.False(booleanAnswer);
}
}
finally
{
PlEngine.PlCleanup();
}
}
Try to close engine in the end of the first method and initialize it in the second again.
You can check this as the answer to the question unless you object.

Using Akavache in Xamarin.Android/Xamarin.iOS

I've successfully got Akavache working for a Windows desktop, .NET 4.5 WPF project, but when I try to build it for the Xamarin (iOS and Android) targets, the BlobCache singleton is not properly initialized. BlobCache.Secure is null. (I've tried both the SQLite and 'vanilla' builds)
I'll be honest, I find the examples/documentation for Akavache a bit thin. I'm not a user of the Reactive stuff, I find much of Paul's code very opaque.
I'm just trying to do some very simple, secure caching of app state for a cross-platform app.
// where we store the user's application state
BlobCache.ApplicationName = "myApp";
BlobCache.EnsureInitialized();
public AppState State
{
get
{
return _appState;
}
set
{
_appState = value;
}
}
public void Load()
{
try
{
State = BlobCache.Secure.GetObjectAsync<AppState>.FirstOrDefault();
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
State = new AppState();
}
}
public void Save()
{
try
{
BlobCache.Secure.InsertObject("AppState", State);
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
So, there are some dumb tricks you have to do right now on Xamarin, that I've only very recently found out. I'm going to add these to the docs (or in the Android case, just fix the bug)
Xamarin.iOS
On iOS, Type.GetType() won't load assemblies, which isn't the same as any other platform. So, you have to run this silly goose code in your AppDelegate:
var r = new ModernDependencyResolver();
(new ReactiveUI.Registrations()).Register((f,t) => r.Register(f, t));
(new ReactiveUI.Cocoa.Registrations()).Register((f,t) => r.Register(f, t));
(new ReactiveUI.Mobile.Registrations()).Register((f,t) => r.Register(f, t));
RxApp.DependencyResolver = r;
(new Akavache.Registrations()).Register(r.Register);
(new Akavache.Mobile.Registrations()).Register(r.Register);
(new Akavache.Sqlite3.Registrations()).Register(r.Register);
Normally, this code runs AutoMagically™.
Xamarin.Android
Registration works fine on Xamarin.Android, but because of what I suspect is a bug in Akavache, you may have to register for AutoSuspend (even if you don't use it).
In all your activities, declare AutoSuspendActivityHelper autoSuspendHelper;
In the constructor, add:
autoSuspendHelper = new AutoSuspendActivityHelper(this);
autoSuspendHelper.OnCreate(bundle);
Override OnPause, OnResume, and OnSaveInstanceState and call the appropriate autoSuspendHelper method i.e:
autoSuspendHelper.OnPause();
More trouble?
Please let me know, either by Emailing me at paul#github.com or filing issues at github/akavache. I've shipped a production application with Akavache that runs on both iOS and Android, and it definitely works, but I realize it might be a bit Tricky™ to get stuff to work.

How do i read the Title property of a GDK.Window

I'm converting an .NET Windows application for Mono to run on Linux (Ubuntu). One of the features depends on a native library (user32.dll). The Mono guide that talks about conversion of applications (Linux Platform Differences) suggests that one approach would be to modify this code.
I'm trying to use GDK to access the Title of a Gdk.Window that I had access through the property Gdk.Global.ActiveWindow. But I found this error at compile time:
Error CS0154: The property or indexer `Gdk.Window.Title` cannot be used in this context because it lacks the `get` accessor (CS0154) (GetActiveWindow)
If i remove the code that reads de Title property of activeW, everything works fine. There is another way to read this property?
Here my unit of work:
using System;
using Gtk;
using Gdk;
using System.Threading;
namespace GetActiveWindow
{
class GdkApp : Gtk.Window
{
public static void Main ()
{
Application.Init ();
new GdkApp ();
Application.Run ();
}
public GdkApp () : base("Simple App")
{
SetDefaultSize (150, 150);
ShowAll();
while (true) {
var activeW = Gdk.Global.ActiveWindow;
Console.WriteLine("Active Window: {0}",activeW.Title); // Where my compile error happens.
Console.WriteLine("Simple App Window: {0}",this.Title); // This code works perfectily.
Thread.Sleep(1000);
}
}
}
}
I think that with Gdk is imposible. Try it with Wnck library giving to a C compiler this '-DWNCK_I_KNOW_THIS_IS_UNSTABLE' and works but with a warning: Unhandled action type _OB_WM_ACTION_UNDECORATE
Sorry I have used genie instead vala.
//valac *.gs --pkg gtk+-3.0 --pkg libwnck-3.0 -X '-DWNCK_I_KNOW_THIS_IS_UNSTABLE'
init
Gtk.init(ref args)
var ventana= new win()
ventana.inicio()
ventana.printinfo()
Gtk.main()
class win:Gtk.Window
won:weak GLib.List of Wnck.Window
def inicio()
var button= new Gtk.Button()
button.clicked.connect(printinfo)
this.add(button)
this.show_all()
def printinfo()
won= Wnck.Screen.get_default().get_windows()
won.foreach(allwin)
def allwin(w:Wnck.Window)
if w.is_skip_tasklist() or w.is_skip_pager()
pass
else
print w.get_name()

Use TAP with wcf EAP generated proxies

I have a Silverlight 5 app, that makes use of a WCF service. The proxy client that has been generated has only asychronous methods (by default, when generating from the SL client).
I want to make use of the Task-based Asynchronous Pattern (TAP), now within VS2012RC.
What is the best approach to consume the async methods from the generated client proxy ?
(the issue is, that the WCF proxy generator creates code that is based on the Event-based Asynchronous Pattern (EAP) and not TAP....)
Based on this document:
http://www.microsoft.com/en-us/download/details.aspx?id=19957
I have found a solution for this.
See code below:
public class MyDataListProvider : IMyDataListProvider
{
private <ObservableCollection<IMyData>> myDataList;
public Task<ObservableCollection<IMyData>> GetMyData()
{
TaskCompletionSource<ObservableCollection<IMyData>> taskCompletionSource = new TaskCompletionSource<ObservableCollection<IMyData>>();
MyWCFClientProxy client = new MyWCFClientProxy();
this.myDataList.Clear();
client.GetMyDataCompleted += (o, e) =>
{
if (e.Error != null)
{
taskCompletionSource.TrySetException(e.Error);
}
else
{
if (e.Cancelled)
{
taskCompletionSource.TrySetCanceled();
}
else
{
foreach (var s in e.Result)
{
var item = new MyData();
item.Name = s.Name;
item.Fullname = s.Fullname;
this.myDataList.Add(item);
}
taskCompletionSource.TrySetResult(this.myDataList);
}
}
};
client.GetMyDataAsync();
return taskCompletionSource.Task;
}
}
Client SL code:
private async void SetMyDataList()
{
this.MyDataList = await this.myDataListProvider.GetMyData();
}
I don't know if it was available in the RC, however as of the SDK 8.0A (the one included with VS2012) svcutil.exe will generate async methods using the TAP pattern.
It will use TAP by default so be sure to NOT include /async as that will make it fall back to the old APM method of generating the methods.
You can see if the version of svcutil is new enough to use the TAP by looking at the first lines of the program it will include that it is at least version 4.0 of the tool.
Microsoft (R) Service Model Metadata Tool [Microsoft (R) Windows (R)
Communication Foundation, Version 4.0.xxxxx.xxxxxx]

Categories