I'm hooking the publish event like this :
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ContentService.Published += ContentService_Published;
}
private void ContentService_Published(global::Umbraco.Core.Publishing.IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
// My code , Send Error
}
When the user is "Saving and publish" a content i want to show the umbraco default error popup for errors with my custom error message.
Is it possible?
Thanks in advance.
In your ContentService_Published method I believe you can do something like:
e.Cancel = true;
e.Messages.Add(new EventMessage("Ouch!", "Better try that again but more gently this time!!!", EventMessageType.Error));
Related
When a DataProvider fetch or count method throws an exception, e.g. because the user is not authorized, how could I handle these exceptions centrally? I know there is HasErrorParameter interface to show error views when there is an exception thrown when routing. But these error views are not triggered when DataProvider throws the exception.
Example:
new AbstractBackEndDataProvider<String, Void>() {
#Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query) {
...
}
#Override
protected int sizeInBackEnd(Query<String, Void> query) {
throw new UnsupportedOperationException("test");
}
}
#Route("failed")
public class FailView extends VerticalLayout
implements HasErrorParameter<UnsupportedOperationException> {...}
Even if I do a try catch within the DataProvider methods, I don't see how I could navigate to the appropriate error view just by using the caught exception and not the view component class (this wouldn't trigger setErrorParameter method).
BTW: I miss the router exception handling topic in Vaadin Flow 13 documentation. I wonder why they removed it.
I believe all Exceptions that don't occur while routing will be given to the ErrorHandler of the VaadinSession the error occured in.
The best way to set the ErrorHandler seems to be to override the sessionInit method in a custom SessionInitListener
You can add a custom SessionInitListener inside the servletInitialized method of a custom VaadinServlet.
class CustomServlet extends VaadinServlet{
#Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
getService().addSessionInitListener(new CustomSessionInitListener());
}
}
And that SessionInitListener (in this example CustomSessionInitListener) has to set the errorHandler of the sessions that get initialized.
class CustomSessionInitListener implements SessionInitListener{
#Override
public void sessionInit(SessionInitEvent event) throws ServiceException {
event.getSession().setErrorHandler(new CustomErrorHandler());
}
}
For further information on how to create your own Servlet take a look at Vaadin's tutorial page(you need to scroll down to "Customizing Vaadin Servlet")
Edit:
To show the error page you need to get Vaadin to reroute to an error. To achieve that we can use an BeforeEnterEvent, BeforeEnterEvents have a rerouteToError method which we can use to let Vaadin show our ErrorView.
But we also want to pass along the Exception instance, so we have to store that as well. I did exactly that with the following class:
#Route("error-view") // Route shown in the user's browser
public class ErrorViewShower extends Div implements BeforeEnterObserver {
// Class to store the current Exception of each UI in
private static class UIExceptionContainer extends HashMap<UI, Exception> {
}
// Method to call when we want to show an error
public static void showError(Exception exception) {
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Creating and setting the exceptionContainer in case it hasn't been set yet.
if (exceptionContainer == null) {
exceptionContainer = new UIExceptionContainer();
VaadinSession.getCurrent().setAttribute(UIExceptionContainer.class, exceptionContainer);
}
// Storing the exception for the beforeEnter method
exceptionContainer.put(UI.getCurrent(), exception);
// Now we navigate to an Instance of this class, to use the BeforeEnterEvent to reroute to the actual error view
UI.getCurrent().navigate(ErrorViewShower.class);// If this call doesn't work you might want to wrap into UI.access
}
#Override
public void beforeEnter(BeforeEnterEvent event) {
UIExceptionContainer exceptionContainer = VaadinSession.getCurrent().getAttribute(UIExceptionContainer.class);
// Retrieving the previously stored exception. You might want to handle if this has been called without setting any Exception.
Exception exception = exceptionContainer.get(UI.getCurrent());
//Clearing out the now handled Exception
exceptionContainer.remove(UI.getCurrent());
// Using the BeforeEnterEvent to show the error
event.rerouteToError(exception, "Possible custom message for the ErrorHandler here");
}
}
Usage of it in combination with the error handler looks like this:
public class CustomErrorHandler implements ErrorHandler {
#Override
public void error(ErrorEvent event) {
// This can easily throw an exception itself, you need to add additional checking before casting.
// And it's possible that this method is called outside the context of an UI(when a dynamic resource throws an exception for example)
Exception exception = (Exception) event.getThrowable();
ErrorViewShower.showError(exception);
}
}
Edit2:
As it turns out that Exceptions occuring inside internal method calls don't get handled by the UI's ErrorHandler or the VaadinSession's ErrorHandler but instead by another error handler which causes the client side to terminate and show the Error Notification,
a solution is to catch the Exceptions inside the methods of the DataProvider and pass them to ErrorViewShower.showError() and still return without any Exception flying the stacktrace upwards. (Or don't throw any Exception yourself and instead simply pass a new to the ErrorViewShower.showError() method).
By returning normally Vaadin doesn't even know something went wrong.
ErrorViewShower.showError() calls ui.navigate, that navigation command seems to get "queued" behind the calls to the DataProvider, meaning the view of the user will change in the same request.
Dataprovider with such an implementation:
new AbstractBackEndDataProvider<String, Void>() {
#Override
protected Stream<String> fetchFromBackEnd(Query<String, Void> query) {
try{
//Code that can throw an Exception here
}catch(Exception e){
ErrorViewShower.showError(e);
//We have to make sure that query.getLimit and query.getOffset gets called, otherwise Vaadin throws an Exception with the message "the data provider hasn't ever called getLimit() method on the provided query. It means that the the data provider breaks the contract and the returned stream contains unxpected data."
query.getLimit();
query.getOffset();
return Stream.of(); //Stream of empty Array to return without error
}
}
#Override
protected int sizeInBackEnd(Query<String, Void> query) {
//Second way i mentioned, but this will not catch any Exception you didn't create, where as the try...catch has no way to let any Exception reach Vaadin.
if(badThingsHappened){
ErrorViewShower.showError(new UnsupportedOperationException("Bad things..."));
return 0;//Exiting without error
}
}
}
I would like to run some code when a user publishes or deletes a page. What is the best way to do this?
I have a custom index service that works as a search for html content, so I would like to submit new content to this service when a user publishes a page in Umbraco. Also I would like to submit a delete to the index service when a user deletes or pages.
Create a class and inhert from IApplicationEventHandler
in the OnApplicationStarting you can create all kind of events
Like this
public class ApplicationEventHandler : IApplicationEventHandler
{
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ContentService.Saving += ContentService_Saved;
ContentService.Published += ContentService_Published;
ContentService.UnPublishing +=ContentServiceOnUnPublishing;
ContentService.Deleting += ContentServiceOnDeleting;
ContentService.Moved +=ContentServiceOnMoved;
MediaService.Saving+=MediaService_Saving;
MemberService.Created+=MemberServiceOnCreated;
MemberService.Deleting += MemberServiceOnDeleted;
}
void ContentService_Published(IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
}
I have default template of MVC4 project and following subscription for UnhandledException event in my Global.asax:
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
protected void Application_Start()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Debugger.Break();
// Some logging code here
}
In my HomeController Index action I simply write:
throw new Exception("Test exception"):
Console application with such subscription works fine. But in MVC project handler call never occurs.
What is wrong with MVC?
UnhandledException callback is not called because when action raise exception its handled by MVC framework and AppDomain doesn't have unhandled exception so its not candidate to be unloaded and it can handle next request.
The shortest way to log exception:
protected void Application_Error(object sender, EventArgs args)
{
Debugger.Break();
Exception error = ((HttpApplication)sender).Context.Server.GetLastError();
// Some logging code here
}
I have written an HTTPModule for the redirection purpose and installed in GAC and referenced in root web.config file. It is working for Team sites very well.
I am using PreRequestHandlerExecute to see the request is page or not and calling
public void Init(HttpApplication context)
{
this.app = context;
this.app.PreRequestHandlerExecute += new EventHandler(Application_PreRequestHandlerExecute);
}
void Application_PreRequestHandlerExecute(object source, EventArgs e)
{
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null)
{
page.PreInit += new EventHandler(Perform_Redirection);
}
}
and in the Perform_Redirection method I am doing the redirection stuff.
void Perform_Redirection(object source, EventArgs e)
{
//logic goes here for redirection
}
The above code working fine for Teamsites but not for Publishing sites. The Page.PreInit is not firing for publishing sites.
Please help me to solve this problem!
I am using PreRequestHandlerExecute, because I need session object and other details otherwise I would have used BeginRequest.
I solved it by moving the redirection code into the PreRequestHandlerExecute event handler
I am writing an Excel 2007 Addin. using VS2008 and .net 3.5, C#.
I catched Microsoft.Office.Interop.Excel.Application's WindowActivate and WindowDeActivate events.
It was surprised to know that WindowActivate and Deactivate only triggers when i switch between two Excel Windows. if i switch to notepad, i expect Deactivate to be triggered, but its not happening. same way from notepad if i switch to excel window, i expect Activate to be triggered but its not happening. It looks like the behaviour indicates windows are MDI-Child windows.
Now what i want to do is get HWnd of Excel's Mainwindow and hook Window Activate and Deactivates using dllimport features.
Can anyone guide to me on this.
Regards
I solved similar problem when writing Excel addin. No dll import is needed. I solved this issue using System.Windows.Forms.NativeWindow class.
At first, I made my own class inherited from NativeWindow class and declared two events Activated and Deactivate in it and finaly overrided WndProc() method to rise these events when message WM_ACTIVATE is passed to the WndProc method. According to "Message" parameter WParm is Excel window activated or deactivated.
public class ExcelWindow: NativeWindow
{
public const int WM_ACTIVATED = 0x0006;
public ExcelWindow():base(){}
//events
public event EventHandler Activated;
public event EventHandler Deactivate;
//catching windows messages
protected override void WndProc(ref Message m)
{
if (m.Msg== WM_ACTIVATED)
{
if (m.WParam.ToInt32() == 1)
{
//raise activated event
if (Activated!=null)
{
Activated(this, new EventArgs());
}
}
else if (m.WParam.ToInt32() == 0)
{
//raise deactivated event
if (Deactivate!=null)
{
Deactivate(this, new EventArgs());
}
}
}
base.WndProc(ref m);
}
}
Then I made in my addin class field "ExcelWindow myExcelWindow" and added following code to OnConnection method of my addin:
ExcelWindow myExcelWindow;
void Extensibility.IDTExtensibility2.OnConnection(object application, Extensibility.ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
{
excel = application as Excel.Application;
myExcelWindow = new ExcelWindow();
myExcelWindow.AssignHandle(new IntPtr(excel.Hwnd));
myExcelWindow.Activated += new EventHandler(myExcelWindow_Activated);
myExcelWindow.Deactivate += new EventHandler(myExcelWindow_Deactivate);
//addin code here
}
void myExcelWindow_Activated(object sender, EventArgs e)
{
//do some stuff here
}
void myExcelWindow_Deactivate(object sender, EventArgs e)
{
//do some stuff here
}
I hope this will help you.
Finally I found one solution..that works only Activate/Deactivate.
This is not the perfect way to do it. But I did not find any good alternative.
This method uses polling. I have to call following function in each 10 ms interval to check focus in/out.
public static bool ApplicationIsActivated()
{
var activatedHandle = GetForegroundWindow();
if (activatedHandle == IntPtr.Zero)
{
return false; // No window is currently activated
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
return activeProcId == procId;
}