I am developing a GWT client-server webapp using GWT-RPC; mostly it seems to work fine but I am stuck with an error retrieving an ArrayList of an IsSerializable type.
Here is the code for the server-side method:
public GWTInvoiceList listInvoices(String enterpriseID, int selection) {
try{
logger.log("ISI getting a listy of invoices "+selection);
PlataccsUser pxuser = (PlataccsUser) getSession().getAttribute(PlataccsConstants.USER);
Enterprise enterprise= pxuser.getEnterprise(enterpriseID);
Clerk clerk= pxuser.getClerk(enterprise);
int i=0;
List<Invoice> invoices =Invoice.getInvoices(enterprise, clerk, selection);
GWTInvoiceList gwinvoices = new GWTInvoiceList();
Iterator<Invoice> it = invoices.iterator();
while (it.hasNext()){
Invoice invoice = it.next();
logger.log("ISI-listInvoices converting invoice "+invoice.getSystemInvoiceNumber());
gwinvoices.add(convert(invoice, clerk));
}
logger.log("ISI-lI, the invoice list is now ready and it lists "+gwinvoices.size()+" invoices");
return gwinvoices;
}catch(Exception px){
logger.log("ISI propblem getting invoice list", px);
return null;
}
}
This code executes without throwing any exception. The GWTInvoiceList return type is a simple wrapper for ArrayList and the GWTInvoice type is known to serialize successfully in other calls. The client side code is:
public InvoiceList(PlataxTabPanel parent, GWTEnterprise gwtEnterprise, int list_selection_type) {
super(parent, gwtEnterprise.getName());
topLabel.setText("List of Invoices");
subHeader.setText("blah blah");
invoiceService.listInvoices(gwtEnterprise.getEnterpriseID(), list_selection_type, invoiceListCallBack);
//table headers:
table.setWidget(0, 0, new ColumnHeaderLabel(LabelText.LIST_INVOICE_NUMBER_HEADER));
table.setWidget(0, 1, new ColumnHeaderLabel(LabelText.LIST_INVOICE_CUSTOMER_HEADER));
table.setWidget(0, 2, new ColumnHeaderLabel(LabelText.LIST_INVOICE_VALUE_DATE_HEADER));
table.setWidget(0, 3, new ColumnHeaderLabel(LabelText.LIST_INVOICE_DUE_DATE_HEADER));
table.setWidget(0, 4, new ColumnHeaderLabel(LabelText.LIST_INVOICE_STATUS_HEADER));
table.setWidget(0, 5, new MoneyColumnHeaderLabel(LabelText.LIST_INVOICE_NET_HEADER));
table.setWidget(0, 6, new MoneyColumnHeaderLabel(LabelText.LIST_INVOICE_TAX_HEADER));
table.setWidget(0, 7, new MoneyColumnHeaderLabel(LabelText.LIST_INVOICE_TOTAL_HEADER));
}
final AsyncCallback<GWTInvoiceList> invoiceListCallBack= new AsyncCallback<GWTInvoiceList>(){
#Override
public void onSuccess(GWTInvoiceList invoices){
Iterator<GWTInvoice> gwit = invoices.iterator();
int row = 1;
while(gwit.hasNext()){
GWTInvoice gwinvoice = gwit.next();
table.setWidget(row, 0, new Label(gwinvoice.getUserno()));
table.setWidget(row, 1, new Label(gwinvoice.getCustomer().getName()));
table.setWidget(row, 2, new Label(DateTimeFormat.getFormat(DateFormats.SHORT_DATE_FORMAT).format(gwinvoice.getValueDate())));
table.setWidget(row, 3, new Label(DateTimeFormat.getFormat(DateFormats.SHORT_DATE_FORMAT).format(gwinvoice.getDueDate())));
table.setWidget(row, 4, new Label(gwinvoice.getStatus()));
table.setWidget(row, 5, new MoneyLabel(gwinvoice.getNet()));
table.setWidget(row, 6, new MoneyLabel(gwinvoice.getTax()));
table.setWidget(row, 7, new MoneyLabel(gwinvoice.getGross()));
row++;
}
}
#Override
public void onFailure(Throwable cause) {
//Debugging code
StackTraceElement[] st = cause.getStackTrace();
String error = "get invoice list failed\n";
error = error+cause.getClass().getName()+"\n";
if (cause instanceof StatusCodeException){
StatusCodeException sce=(StatusCodeException) cause;
int sc = sce.getStatusCode();
error=error+"Status Code:"+ sc+"\n";
}
for (int i=0; i<st.length; i++){
error = error + st[i].toString()+ "\n";
}
Window.alert(error);
}
};
The call always fails with a 500 status code and therefore triggers the OnFailure method of the AsyncCallback inner class.
I am somewhat at a loss to work out why because there is no server-side error.
The problem is one of serialization on the server side, but I can't see where it's coming from. I have overridden OnAfterResponseSerialized to probe things and it isn't called - (it is called by other methods in the same service implementation class, so the probe is working).
From the javadocs, processCall() should be throwing a SerializationException. I need to catch it and see what's going on.
What does the GWTInviceList code look like?
I'm guessing you don't have a no-parameter constructor for the GWTInvoiceList class.
This code:
/**
* catches the SerializationException for forensic examination.
*/
#Override
public String processCall(String payload) throws SerializationException{
try{
return super.processCall(payload);
}catch(SerializationException se){
logger.log("Xservlet serialisation excption", se);
throw se;
}
}
added to the service implementation class catches the SerializationException so I can trace the aberrant object.
Related
I tried for the first time using TestCase as explained here.
I normally got the category name (for debug purpose) like this:
lstCategories = (System.Collections.IList)NUnit.Framework.TestContext.CurrentContext.Test.Properties["Category"];
and then found the category name like this:
(string)lstCategories[0]
But when I use TestCase I could not get it (it is empty).
Please help.
Did you setup your [Test] method as in the example which you provided? There is an example of how to pass data to the test method:
private static IEnumerable<TestCaseData> AddBrowserConfs()
{
yield return new TestCaseData("chrome", "72.0", "Windows 10");
yield return new TestCaseData("internet explorer", "11.0", "Windows 10");
yield return new TestCaseData("Safari", "11.0", "macOS High Sierra");
yield return new TestCaseData("MicrosoftEdge", "18.0", "Windows 10");
}
[Test, TestCaseSource("AddBrowserConfs")]
public void DuckDuckGo_TestCaseSource_Demo(String browser, String version, String os)
{
As you can see, values from AddBrowserConfs are passed as arguments in DuckDuckGo_TestCaseSource_Demo. Does this answer your question?
With test cases you are not getting Category name because its not set properly. You need to set it with each test cases as below:
[Test]
[TestCase(12, 4, Category = "MyCat")]
[TestCase(10, 6, Category = "MyCat")]
public void Test2(int a, int b)
{
Assert.AreEqual(a + b, 16);
var catName = TestContext.CurrentContext.Test.Properties.Get("Category").ToString();
Console.WriteLine(catName);
}
OR if you are using TestCaseSource, add Category name as below:
[Test]
[TestCaseSource(typeof(AddCases), Category = "MyCat")]
public void Test2(int a, int b)
{
Assert.AreEqual(a + b, 16);
}
public class AddCases : IEnumerable
{
public IEnumerator GetEnumerator()
{
yield return new object[] { 8, 8 };
yield return new object[] { 10, 6 };
yield return new object[] { 12, 4 };
}
}
Hope this helps.
I'm running the code below to purposely throw JsonReaderException. It correctly gives the exception message of "Could not convert string to boolean: aaa. Path 'Active', line 3, position 17."
Is there any way to get the value that has failed the validation directly from the JsonReaderException so I don't have to parse the exception message?
string json = #"{
'Email': 'james#example.com',
'Active': 'aaa',
'CreatedDate': '2013-01-20T00:00:00Z',
'Roles': [
'User',
'Admin'
]
}";
try
{
Account account = JsonConvert.DeserializeObject<Account>(json);
Console.WriteLine(account.Email);
}
catch (JsonReaderException exc)
{
// Do Something
}
It appears that the offending value is not saved as a property in JsonReaderException. The only possible location for this value would be the Exception.Data dictionary, however Json.NET does not add anything here.
However, with some work you can leverage Json.NET's serialization error event handling functionality to directly access the bad value at the time the exception is thrown. First, define the following helper method and ErrorEventArgs subtype:
public class ErrorAndValueEventArgs : Newtonsoft.Json.Serialization.ErrorEventArgs
{
public object ReaderValue { get; } = null;
public ErrorAndValueEventArgs(object readerValue, object currentObject, ErrorContext errorContext) : base(currentObject, errorContext)
{
this.ReaderValue = readerValue;
}
}
public static partial class JsonExtensions
{
public static TRootObject Deserialize<TRootObject>(string json, EventHandler<ErrorAndValueEventArgs> error, JsonSerializerSettings settings = null)
{
using (var sr = new StringReader(json))
using (var jsonReader = new JsonTextReader(sr))
{
var serializer = JsonSerializer.CreateDefault(settings);
serializer.Error += (o, e) => error(o, new ErrorAndValueEventArgs(jsonReader.Value, e.CurrentObject, e.ErrorContext));
return serializer.Deserialize<TRootObject>(jsonReader);
}
}
}
Now you will be able to access the value of JsonReader.Value at the time the exception was thrown:
object errorValue = null;
try
{
Account account = JsonExtensions.Deserialize<Account>(json, (o, e) => errorValue = e.ReaderValue);
Console.WriteLine(account.Email);
}
catch (JsonException exc)
{
// Do Something
Console.WriteLine("Value at time of {0} = {1}, Data.Count = {2}.", exc.GetType().Name, errorValue, exc.Data.Count);
// Prints Value at time of JsonReaderException = aaa, Data.Count = 0.
}
Notes:
Since you must manually create your own JsonTextReader, you will need to have access to the JSON string (or Stream) for this approach to work. (This is true in the example shown in your question.)
A similar technique for capturing additional error information is shown in JsonSerializationException Parsing.
You might want to enhance ErrorAndValueEventArgs to also record JsonReader.TokenType. In cases where the reader is positioned at the beginning of a container (object or array) at the time an exception is thrown, JsonReader.Value will be null.
Demo fiddle here.
I have two webapi controllers in my MVC 5 project, one in the main domain:
namespace VincConsultancy.Controllers
{
public class QuestionGroupController : ApiController
{
//...
public IEnumerable<SAQQuestionGroup> Get(int id = 0)
{
var groups = (from g in repository.SAQQuestionGroups
where g.RequirementId == id
select g).ToList();
if (groups.Count == 0)
{
string message = string.Format("Groups with Req id = {0} not found", id);
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message)
);
}
return groups;
}
}
}
The other one in the area domain:
namespace VincConsultancy.Areas.admin.Controllers
{
public class SAQGroupsController : ApiController
{
//...
public IEnumerable<SAQGroup> Get(int id = 0)
{
var groups = (from g in this.dbCnxt.SAQQustnGroups
where g.RequirementId == id
select g).ToList();
if (groups.Count == 0)
{
string message = string.Format("Groups with Req id = {0} not found", id);
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message)
);
}
return groups;
}
}
}
In both controllers, I return error messages by throwing HttpResponseException. Visual Studio pauses the execution at the line of 'throw new HttpResponseException' only in the controller in the admin area, saying an exception occurs but was not handled by user code, that doesnt affect the functionality though, i just need to press the continue button every time. However it doesnt happen to the other controller. So, I am wondering if there is some mechanism handling the exceptions in main domain automatically. The throw-exception line is not supposed to be caught by my code, how should I get rid of visual studio breaking there?
I am currently working on MVC4 in VS2010-SP1. I made one of the function in
the controller class Asynchronous. As part of that I made the controller class
derived from AsyncController and added the below two methods ( see code section 1 and
2 below). one method ending with Async(See Code Section 1 ) and another method ending
with Completed ( See Code Section 2 ). The problem is in the model class I am trying
to access my webservice with credentials from HttpContext ( See Code below 3 ). The
context is going null when making an asynchronous call. ie, In the new thread
httpcontext is not available. How to pass the context from main thread to new threads
created.
Code Section 1
public void SendPlotDataNewAsync(string fromDate, string toDate, string item)
{
AsyncManager.OutstandingOperations.Increment();
var highChartModel = new HighChartViewModel();
Task.Factory.StartNew(() =>
{
AsyncManager.Parameters["dataPlot"] =
highChartModel.GetGraphPlotPointsNew(fromDate, toDate, item);
AsyncManager.OutstandingOperations.Decrement();
});
}
Code Section 2
public JsonResult SendPlotDataNewCompleted(Dictionary<string, List<ChartData>>
dataPlot)
{
return Json(new { Data = dataPlot });
}
Code Section 3
public List<MeterReportData> GetMeterDataPointReading(MeterReadingRequestDto
meterPlotData)
{
var client = WcfClient.OpenWebServiceConnection<ReportReadingClient,
IReportReading>(null, (string)HttpContext.Current.Session["WebserviceCredentials"] ??
string.Empty);
try
{
return
ReadReportMapper.MeterReportReadMap(client.GetMeterDataPointReading(meterPlotData));
}
catch (Exception ex)
{
Log.Error("MetaData Exception:{0},{1},{2},{3}",
ex.GetType().ToString(), ex.Message, (ex.InnerException != null) ?
ex.InnerException.Message : String.Empty, " ");
throw;
}
finally
{
WcfClient.CloseWebServiceConnection<ReportReadingClient,
IReportReading> (client);
}
}
HttpContext.Current is null because your task is executed on a pool thread without AspNetSynchronizationContext synchronization context.
Use TaskScheduler.FromCurrentSynchronizationContext():
Task.Factory.StartNew(() =>
{
AsyncManager.Parameters["dataPlot"] =
highChartModel.GetGraphPlotPointsNew(fromDate, toDate, item);
AsyncManager.OutstandingOperations.Decrement();
},
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
Just came across the latest build of Mono.CSharp and love the promise it offers.
Was able to get the following all worked out:
namespace XAct.Spikes.Duo
{
class Program
{
static void Main(string[] args)
{
CompilerSettings compilerSettings = new CompilerSettings();
compilerSettings.LoadDefaultReferences = true;
Report report = new Report(new Mono.CSharp.ConsoleReportPrinter());
Mono.CSharp.Evaluator e;
e= new Evaluator(compilerSettings, report);
//IMPORTANT:This has to be put before you include references to any assemblies
//our you;ll get a stream of errors:
e.Run("using System;");
//IMPORTANT:You have to reference the assemblies your code references...
//...including this one:
e.Run("using XAct.Spikes.Duo;");
//Go crazy -- although that takes time:
//foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
//{
// e.ReferenceAssembly(assembly);
//}
//More appropriate in most cases:
e.ReferenceAssembly((typeof(A).Assembly));
//Exception due to no semicolon
//e.Run("var a = 1+3");
//Doesn't set anything:
//e.Run("a = 1+3;");
//Works:
//e.ReferenceAssembly(typeof(A).Assembly);
e.Run("var a = 1+3;");
e.Run("A x = new A{Name=\"Joe\"};");
var a = e.Evaluate("a;");
var x = e.Evaluate("x;");
//Not extremely useful:
string check = e.GetVars();
//Note that you have to type it:
Console.WriteLine(((A) x).Name);
e = new Evaluator(compilerSettings, report);
var b = e.Evaluate("a;");
}
}
public class A
{
public string Name { get; set; }
}
}
And that was fun...can create a variable in the script's scope, and export the value.
There's just one last thing to figure out... how can I get a value in (eg, a domain entity that I want to apply a Rule script on), without using a static (am thinking of using this in a web app)?
I've seen the use compiled delegates -- but that was for the previous version of Mono.CSharp, and it doesn't seem to work any longer.
Anybody have a suggestion on how to do this with the current version?
Thanks very much.
References:
* Injecting a variable into the Mono.CSharp.Evaluator (runtime compiling a LINQ query from string)
* http://naveensrinivasan.com/tag/mono/
I know it's almost 9 years later, but I think I found a viable solution to inject local variables. It is using a static variable but can still be used by multiple evaluators without collision.
You can use a static Dictionary<string, object> which holds the reference to be injected. Let's say we are doing all this from within our class CsharpConsole:
public class CsharpConsole {
public static Dictionary<string, object> InjectionRepository {get; set; } = new Dictionary<string, object>();
}
The idea is to temporarily place the value in there with a GUID as key so there won't be any conflict between multiple evaluator instances. To inject do this:
public void InjectLocal(string name, object value, string type=null) {
var id = Guid.NewGuid().ToString();
InjectionRepository[id] = value;
type = type ?? value.GetType().FullName;
// note for generic or nested types value.GetType().FullName won't return a compilable type string, so you have to set the type parameter manually
var success = _evaluator.Run($"var {name} = ({type})MyNamespace.CsharpConsole.InjectionRepository[\"{id}\"];");
// clean it up to avoid memory leak
InjectionRepository.Remove(id);
}
Also for accessing local variables there is a workaround using Reflection so you can have a nice [] accessor with get and set:
public object this[string variable]
{
get
{
FieldInfo fieldInfo = typeof(Evaluator).GetField("fields", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo != null)
{
var fields = fieldInfo.GetValue(_evaluator) as Dictionary<string, Tuple<FieldSpec, FieldInfo>>;
if (fields != null)
{
if (fields.TryGetValue(variable, out var tuple) && tuple != null)
{
var value = tuple.Item2.GetValue(_evaluator);
return value;
}
}
}
return null;
}
set
{
InjectLocal(variable, value);
}
}
Using this trick, you can even inject delegates and functions that your evaluated code can call from within the script. For instance, I inject a print function which my code can call to ouput something to the gui console window:
public delegate void PrintFunc(params object[] o);
public void puts(params object[] o)
{
// call the OnPrint event to redirect the output to gui console
if (OnPrint!=null)
OnPrint(string.Join("", o.Select(x => (x ?? "null").ToString() + "\n").ToArray()));
}
This puts function can now be easily injected like this:
InjectLocal("puts", (PrintFunc)puts, "CsInterpreter2.PrintFunc");
And just be called from within your scripts:
puts(new object[] { "hello", "world!" });
Note, there is also a native function print but it directly writes to STDOUT and redirecting individual output from multiple console windows is not possible.