The silverlight object tag accept an 'onerror' parameter which calls back to a piece of javascript of your choice. The default implementation which is generated by the Visual Studio template assembles a descriptive message and throw it as an Error (which lets e.g. IE display the little warning triangle).
It seems to me that each time this callback is fired our silverlight instance is dead and you need to refresh the page. Is this a reasonable deduction?
Another issue is how to best handle this callback. Showing the little warning icon is somewhat developer-centric and it doesn't allow us (the developers) to discover what is actually failing in production when it is run on a customer machine. What are people doing with this? A couple of our own (more or less concrete) ideas are:
Send the error message back to the server via some exposed endpoint
Remove hide the silverlight object, show a nicer and more descriptive message to the user and a 'refresh' link to start up the silverlight page again (we run a full-sized silverlight application so if the silverlight object isn't working, the customer might as well reload anyway)
Somehow reload the object tag automatically to avoid having the customer perform any actions to get going again (perhaps combined with some notice to the customer that the 'system' restarted)
Ideas, thoughts, best practices, anti-patterns? What are you guys doing (except ensuring that the silverlight app never fails, but that's another discussion)?
I like a nice error reporting in the form of a "form" using SilverlightFX grab the source http://github.com/NikhilK/silverlightfx/tree/master , check it out very cool framework otherwise basically would be just a summary of the error, the ability to send it via upload that emails to support and an "oops we goofed" title :) I handle all unhandled expetions in this way, there is also a nice article on handling the errors by type using a dictionary
http://www.netfxharmonics.com/2009/04/Exception-Handlers-for-Silverlight-20 also a favorite of mine
. Hope this helps
I recommend you change how you're instantiating the Silverlight control. Instead of using the object tag, you can call Silverlight.CreateObjectEx() in the Silverlight.js file. This is probably a little more natural for your scenario. If it fails, you can call it again which is simpler than trying to reload object tags. Ex:
Silverlight.createObjectEx(
{
source: '/../VideoPlayer.xap',
parentElement: document.getElementById('movieplayerDiv'),
id: 'VideoPlayer',
properties: {
width: '100%',
height: '100%',
background: '#FFd9e3d7',
inplaceInstallPrompt: false,
isWindowless: 'false',
version: '2.0'
},
events: {
onError: onSLError,
onLoad: onSLLoad
},
initParams: "...",
context: null
});
function onSLLoad(sender, args) {
}
function onSLError(sender, args) {
// alert('error');
}
Other thoughts:
If your javascript error handler fires, the instantiation has failed. Silverlight will not suddenly come back to life by itself. Instead, call CreateObjectEx to give it another shot ;)
There are 2 kinds of terminal errors in Silverlight. 1) Managed errors (hit the managed Application_UnhandledException method). Note that some errors may not even get to this point. If the managed infrastructure can't be loaded for some reason (out of memory error maybe...), you won't get this kind of error. Still, if you can get it, you can use a web service (or the CLOG project) to communicate it back to the server. 2) Javascript errors. These are what you're getting right now. I recommend bouncing these back to your server with JQuery (or Javascript library of preference). Something like:
$.post(this.href, { func: "countVote" },
function(data) {...}
How you handle this on the server, of course, is dependent on what your server stack looks like. It's super easy in MVC, btw.
Related
I am building a React app (with react-redux, redux-saga, and axios), and
I need advice on how to arrange my project for displaying user-friendly error messages.
(It is up to me to decide what and how I display to the user)
In particular, I would like to get answers to the following questions:
Should I display a message based on the status code?
Should I break down the errors to client / server / other errors and what are the benefits of that? (based on example from Axios)
Where should I keep the error messages, in the component itself, in a config file (I would like to see an example of such a file)?
How would my redux state tree look?
Should I dispatch an action for every error based on the status code?
I would appreciate any suggestions or real-world examples.
Here are some examples of error responses from our backend:
Request URL: https://example.com/api/call/123
Request Method: POST
Status Code: 400 Bad Request
Request URL: https://example.com/api/call/123
Request Method: PUT
Status Code: 409 Conflict
Request URL: https://example.com/api/user/me/
Request Method: GET
Status Code: 401 Unauthorized
It basically depends on what method you are trying to display the message, For instance, in our own projects, We are using a global snack bar component to display errors if any have occurred during the requests.
Most of the time users don't care about the status code, if you want not to be very specific then you can display a simple alert/snack bar for example: "Sorry, Some error occurred".
If you are sure that you do need to show specific errors to the user the I definitely recommend a constant file for errors which will store all your error message, You can keep them in constants directory in the store folder so maybe even in /helpers, It depends on your choice.
Yep, you can definitely divide your errors based on if the error was on the server or the client-side.
I don't think the redux tree will change if you're not managing errors in the tree. If you want to, definitely use a snack bar/alert reducer on the top of the tree
You may not want to show the same error for a status code in each of different components, Otherwise, if you want to, You can use it but that would add a lot of unnecessary code into your requests.
For our projects, since we are using i18 for internationalization, We have a snack bar reducer and the action folder, We import the snack bar actions in our sagas and just display a simple error message ( You definitely can customize it for your needs accordingly), That's all,Keep it simple.
yield put(Actions.apiRequest);
try {
const res = yield axios.put('/todo/', updateData);
if (res.data.status === 'success') {
yield put(Actions.fetchTodos(todoID));
yield put(snackbarSuccess('Todo Saved Successfully !'));
} else {
throw new Error();
}
} catch (error) {
yield put(Actions.apiError);
yield put(snackbarError(REQUEST_FAIL)); // an imported constant
}
Some basic code behind my implementation.
1) Assuming you're also doing the BE or can ask someone to adjust the response - It might be best to return a body with your API error response, and avoid just HTTP status codes - if possible. That could then contain an error 'code' that maps to a message on your front-end, as well as field name which can be really helpful for displaying errors in the right place on forms, etc. alternatively, the entire message could come from the BE and the FE simply display it. I work on an enterprise-level codebase that uses both these methods.
2) Regarding error message, i'd always store them in a common file but beyond that up to you really. It sort of depends on how you implement #1. Personally I like error 'codes' stored in an enum file, which correspond to a message because you can then do other logic from that (e.g. don't display the rest of a form if error X is triggered, use a custom message for the error code in one situation or fall back to a default
3) Not sure - I guess you'd do that if you want to log server-side errors but show client. Where I work we differentiate purely for different logging categories I think.
4) Again depends on your implementation - somewhat up to you. Some form packages will handle this for you in redux. Others will just use local state and not redux for this.
5) Would make sense to, yes. Again if you look a custom error code returned in the body of the API call that'll give you more flexibility.
I hope that gives you some ideas, based on my experience rather than any set way of thinking.
have a look at https://reactjs.org/docs/error-boundaries.html as well, and if you haven't already REST APIS / best practice for REST API: https://blog.restcase.com/rest-api-error-codes-101/
Within a Codename1 app, I'm getting a CrashReport: java.lang.NullPointException: Attempt to invoke virtual method 'void android.graphics.Point.setAntiAlias(boolean)' on a null object reference. This seems to occur after I invoke a "show()" on the main form of my application.
Note that the code runs fine in the simulator, but consistently gets this error prior to doing the "show()" on Android.
Interestingly, if I put a Dialog like this:
Dialog.show("Wait a sec", "Showing interrupt point", "OK", null);
before the .show(), and then click "OK", then everything runs well with no exceptions at all.
But a sleep(5000) instead of the Dialog does not help - still get the exception. So it at least seems like its not a race condition.
I have try-catches wrapped around all of the potentially offending code, and have NOT been able to isolate this. It always gets caught by the CrashReport, and only when running on the Android device.
Any ideas?
The symptoms to this one are pretty strange (i.e. workaround with a Dialog), and it would be interesting to have an explanation. However, since deprecated cn1 (Map) code has seemingly been implicated, I'm going to let this one go and replace this code with the latest Google native maps code. If it recurs, I will post another question then.
One of the requirements of the project I am working on is that I log the connections made to the site, due to the amount of processing being done to get as much information as possible I would like to process this after the page has been sent back to the user.
At the moment I am running my code in the afterFilter of my appController:
public function afterFilter(Event $event){
$log_request = new RequestsController;
$log_request->log_request();
}
I am attempting to run this in afterRender of my appController:
public function afterRender(Event $event, $viewFile){
$log_request = new RequestsController;
$log_request->log_request();
}
But I can not seem to get the code to execute or if it does then I do not know how to find out what the error being thrown is.
If somebody can point me towards an example of this being done or a concurrent method of doing this (it needs to be logged within a second of the request) I would appreciate it.
$log_request = new RequestsController; you don't instantiate controllers inside controllers. You want to learn the MVC design pattern first when using a MVC based framework or you'll end up with a non maintainable piece of horrible spaghetti code. I recommend you to do the blog tutorial to get a basic understanding.
If somebody can point me towards an example of this being done or a concurrent method of doing this (it needs to be logged within a second of the request) I would appreciate it.
Read this chapter: CakePHP Logging Taken from there:
Logging data in CakePHP is easy - the log() function is provided by the LogTrait, which is the common ancestor for many CakePHP classes. If the context is a CakePHP class (Controller, Component, View,...), you can log your data. You can also use Log::write() directly.
Add the log trait to the AppController, pass the request to the log() method and configure the logging to log these requests to whatever you prefer either in afterRender() or if you want to do it really late, do it in __destruct().
Is this:
Web web = context.Web;
context.Load(web, w => w.Language);
context.ExecuteQuery();
or something similar in order to load web.Language with context.ExecuteQuery() possible in a silverlight client? The above code was taken from
http://www.dev4side.com/community/blog/2011/1/5/incorrect-dates-taken-from-sharepoint-2010-client-object-model.aspx
When I do so, instantiating the web's Language property always yields
Microsoft.SharePoint.Client.PropertyOrFieldNotInitializedException
Btw, this code is in an extra thread (not the UI thread). I know that there is context.loadQueryAsync() but I already have an extra thread and would like to keep things together.
As far as I've tried this code works ok. Do you maybe access some other properties of the Web object that are not loaded? You'd have to include them also in your load method.
I'm working on a out of browser Silverlight app that provides some MS Office Communicator 2007 controls. I'm using the Automation SDK. The docs that were installed with the SDK state that there's a MyGroups property in the IMessenger2 interface, which will return the groups that a user has defined, but when I try to use it, I get a NotImplementedException. Here's the code that I'm using:
dynamic communicator = AutomationFactory.CreateObject("Communicator.UIAutomation");
communicator.AutoSignin();
foreach (dynamic g in communicator.MyGroups)
{
//Do something with the group
}
If I replace MyGroups with MyContacts, I can get the contact list just fine. Do I have to do something different to access properties in the IMessenger2 interface? I've seen a few things on the web that say that MyGroups was deprecated for Windows Messenger, but from the docs, it seems like it should be available for MS Office Communicator.
If I can't use MyGroups, is there another way to get the groups that a user has created?
The problem here is that the MyGroups property is marked as NotScriptable, meaning you can't call it in the way you are doing i.e. using the AutomationFactory. For security reasons, some properties and methods in the Automation API are not scriptable - this is to avoid malicious pages automating Communicator and carrying out certain tasks without you knowing.
It looks like the COM interop in Silverlight is treated in the same way as e.g. creating and calling the API from VBScript, so you won't be able to access any of the non-scriptable properties and methods. See the reference for details of which properties and methods are not scriptable.
I'm guessing this is going to seriously hobble your app. I think what's hurting you is the decision to go with Silverlight OOB. Is there any way you could use WPF (or even winforms) rather than Silverlight? If you did this, you could reference the API directly, and have full access to all properties/methods.
Otherwise, I can't think of too many options. You can't trap the OnContactAddedToGroup event, as this is not scriptable.
It might be possible to wrap the API with a .NET assembly, and expose it via COM, then instantiate it in the same way - but the Not Scriptable might still be respected in that case, so it won't buy you anything. Hard to say without trying it, and still a fairly horrible solution.
Edit: I've just given the wrapper method a try (needed to do something similar as a proof of concept for a customer), and it seems to work. This is the way I did it:
Create a new .NET class library. Define a COM interface:
[ComVisible(true)]
[Guid("8999F93E-52F6-4E29-BA64-0ADC22A1FB11")]
public interface IComm
{
string GetMyGroups();
}
Define a class that implements that interface (you'll need to reference CommunicatorAPI.dll from the SDK):
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[GuidAttribute("C5C5A1A8-9BFB-4CE5-B42C-4E6688F6840B")]
[ProgId("Test.Comm.1")]
public class Comm : IComm
{
public string GetMyGroups()
{
var comm = new CommunicatorAPI.MessengerClass();
var groups = comm.MyGroups as IMessengerGroups;
return string.Join(", ", groups.OfType<IMessengerGroup>().Select(g => g.Name).ToArray());
}
}
Build, and register using RegAsm. Then call from the OOB silverlight app:
dynamic communicator = AutomationFactory.CreateObject("Test.Comm.1");
MessageBox.Show(communicator.GetMyGroups());
Note, the same technique also works using the Lync API:
public string GetMyGroups()
{
var comm = LyncClient.GetClient();
return string.Join(", ", comm.ContactManager.Groups.Select(g => g.Name).ToArray());
}
Although this works, I can't really say whether it's a good practice, as it's working around a security restriction which was presumably there for a good reason. I guess the worst that could happen is that a malicious web page could potentially use the component, if it knew the ProgId of the control.
Edit: Also, using this method you'd need to be careful about memory leaks, e.g. make sure you're releasing COM objects when you're finished with them - easy enough to do, just needs a little discipline ;o)