How to perform web service call after updating a content part in Orchard? - asp.net

I have a Web API service that I have managed to use to pull values into a ContentPart by using the method outlined here: How to change Orchard record repository.
Now, what I want to do is update the values of the properties on my ContentPart and have the update performed via a Web API call. I think I'm close, but just can't get an update method to fire.
In my Handler, I have added a handler for OnUpdate. I can see my OnUpdate method get registered, but it never executes.
So my question is: Is this the correct handler event to use? And if so, how can I get it to trigger?
I should add that I am accessing the ContentPart through a Controller, as opposed to a Driver.

OnUpdating / OnUpdated get fired whenever you call IContentManager.UpdateEditor(item). In the default scenario this happens when you hit "Save" button when editing your content item.
I don't quite get what you mean by "accessing the ContentPart through a Controller"?
Do you have a custom controller that handles the item editor rendering and it's postback?
Or are you creating and updating some items in code, without using the built-in editors at all?
In the former case, you need to ensure that
IContentEditor.UpdateEditor(item) gets called for the whole content
item inside the POST action (same way it does in the default
controller - Core\Contents\Controllers\AdminController.cs).
In the latter, which I guess might be the case here, OnUpdating /
OnUpdated won't be fired and you need to call the web service on
your own from the controller action, as Bertrand pointed out in the comments.
There is also a third option available and I found it particularly useful in similar cases:
Use LazyField<T> as a backing field for those part properties you need to push to web service after update.
Put the code that calls web service inside that lazy field's setter (set this up during handler OnActivated event).
Now, whenever your property gets updated, a call to web service will be made, ie. the lazy field will act a a transparent proxy between your web service and current code.
For examples how to work with lazy fields take a look into CommonPartHandler class and methods LazyLoadHandlers and PropertySetHandlers.

Related

Messaging Centre - Subscribing Event in the ViewModel Constructor

I am trying to send data from one ViewModel to another using Messaging Centre.
I have subscribed the event in 2nd ViewModel's constructor. But the event is not subscribed as the constructor is not compiled until I open the page/view corresponding to the ViewModel.
I am using MVVM Light, until now I had an understanding that the VM's constructor are compiled when ViewModelLocator is called at the app startup.
Can someone help me understand this better and how can I subscribe the event i.e. compile the constructor without the VM being called.
Perhaps you are thinking about this in the wrong way. Without seeing code it's difficult to see what you are trying to achieve exactly, but what you could do is subscribe to the event elsewhere in your app, for example in your App.xaml.cs. When the event fires, at that point navigate to a new page of type ViewModel2 and pass any details required as a navigation parameter.

How can I do a partial page update with ajax using Sitecore?

I have a specific page (sitecore content item) in my web application composed of a sitecore layout and many sublayouts. One of those sublayouts is a user control that I would like to have refreshed once a certain button is clicked. I would like only that sublayout to be refreshed and the rest of the page to remain unchanged (typical ajax situation here). How do I accomplish this with sitecore when all of my sitecore content items are directly related to a full page in my web application (layout with sublayouts)? In my case, I want to use ajax to return the content of a specific, single sublayout only. What is the best practice for this kind of ajax situation with sitecore? I'm using sitecore 6.5.
Since you use the phrase "partial page update", I assume you are using an UpdatePanel. This doesn't really function any different than it would in a traditional ASP.NET application. You will handle the button click in a server-side handler method, modify properties on controls and let the update panel handle the rest.
If you are not using update panel, you have a few options depending on exactly what you want to achieve.
Typically, if you are clicking a button to trigger an ajax request, you are posting some data back to the server. For this case you would usually set up a web service to process the data and return some result. Your service can access Sitecore data, but does not utilize the Sitecore presentation engine.
Another option would be to make the request to a Sitecore page (possibly the same as the original request), but include a querystring parameter to trigger a different device. You could configure this device to render JSON, XML or a fragment of HTML rather than the normal Layout and battery of sublayouts.
Another option would be to use the Sitecore Item Web API. If you go this route, you will have another array of options (and a bit of a learning curve as well). Start by reading the documentation on SDN or some of the many blog posts on the topic.
There are a number of options available for achieving asynchronous behavior. None of these really relate to Sitecore directly, however, there are some Sitecore specific things to watch out for which I have highlighted below.
UpdatePanel Control
If you are performing something trivial where ultra-fast performance isn't a concern, simply wrap your button (and any other .NET controls that you would
like updated) in an UpdatePanel Control. You will also need to drop
a ScriptManager control into your base layout near the top inside
the <form> element. NOTE: When using this method, you will need to ensure that that your Sublayout does NOT have caching enabled, otherwise your button will not postback properly
Create your own web service
In this scenario, there are many client-side frameworks available for achieving the same result. My preferred method is to hook onto the client-side button click event with jQuery, prepare a request object, and post it to the server (getting back the information you need to update the client).
Here are a number of web service options that work with Sitecore - allowing you to have access to the Sitecore.Context and all of the subsequent Sitecore APIs.
Create an empty ASPX Web Form that accepts parameters as query strings. In the Page_Load method, do some work with the parameters and write directly to the response using Response.Write(). A JavaScriptSerializer comes in handy for serializing to JSON, just be sure to set Response.ContentType = "text/javascript";
Create an ASMX Web Service and decorate your methods with [WebMethod] (or [WebMethod(EnableSession = true)] if you need access to Session data).
Use MVC Controllers (ex: ASP.NET Web Api) to create an API. I believe there are some issues to work around in Sitecore 6.5 as described here.
Since this is all contained within a single Sublayout, you could simply use a standard <asp:UpdatePanel> surrounding your button and the usercontrol. In the code-behind, you can then do whatever databinding / data retrieval necessary to update the content of the usercontrol.
Note, if the button was on a different sublayout to the one where the content needs to be updated, you can use the approach described in this question as long as both controls have their content within <asp:UpdatePanel>.
In answer to your other question:
What is the best practice for this kind of ajax situation with sitecore?
There's not really a Sitecore-specific best practice for this sort of thing. In this case, any approach which works for plain ASP.NET will also work with Sitecore. The approach I described above is probably the simplest and quickest to implement, but you could also do this via jQuery and ajax to call a web service to load updated content.

Avoid hidden field in the web forms

I have a web page and a modal dialog page. On clicking the save button in the show modal dialog. closes the window and returns a value. Now when the
control reaches the JavaScript function of the parent window . I wnt to perform some database operation on the basis of this returned ID.
I am using the following approach to utilize this returned value.
Keeping it in the hidden field and populating the returned value in hidden control.
keeping a hidden button in the parent window, performing the click event when control comes back to JavaScript function of the parent page. Thus in the server side button handler get the value from hidden field and perform database operation on the basis of returned value.
Is this approach fine. Or I can get rid of hidden field
That's not terribly bad provided the ID returned is not sensitive information that someone can use to modify a record that doesn't belong to him. One can perfectly manipulate this ID on the client side for any other ID and have your logic update a different record from what you intended.
If all you are doing is calling a server side method passing this ID; why don't you do the whole update from the pop-window itself (at that point you already know the ID)?
If the parent window (page) is meant to be updated; you can just perform a normal refresh of the page (ie. use window.location to redirect the user to the same page so he can see the update or use Response.Redirect to the same page.)
What you're probably looking for is called AJAX. With AJAX you can communicate with your web server from within your JavaScript code directly. No HTML form posts are required then. You might want to look at frameworks like JQuery. These have easy implementations (cross browser wrappers) to send HTTP requests via AJAX.
Note: I just noticed, you are using ASP.NET. Take a look at ASP.Net AJAX Page Methods.

Intercept Page object creation to hook up events

I'm looking for a way to intercept the ASP.NET processing pipeline in such a way to be able to register event handlers to all events on the Page class. The reason is, I need to maintain a session-bound instance of a component that needs to be notified of all important Page events, starting from OnPreInit.
There's an arbitrary number of Page descendants in the application, which are not under my control. Hence I cannot use an approach like using a single custom descendant, that would notify the session-bound component, as a base class for all pages in the web application.
I don't think creating a custom IHttpHandler or IHttpModule implementation would solve the problem. Also note I cannot create a custom HttpApplication descendant.
It isn't going to be an elegant process to do what you are looking at, especially if you need to handle multiple page events, but in theory it is fully possible from within the Global.asax to setup handlers that you need for each and every page.
The trick here is to add your code to the global.asax in the PreRequestHandlerExecute method, from here you can get access to the HttpApplication object, get access to the page from there, and then register your events. This process is necessary as a new page instance is created for every page that is processed.
Now, other options as you know are far more elegant, but this should get to where you need to be. One helpful tutorial I found although around Themeing shows you the whole process here.
EDIT:
After seeing your comment, yes, you can simply do what I'm stating above, in a custom HttpModule. The article I linked even shows you that process :)
Without knowing more about what you're trying to accomplish it really sounds like you do indeed want to create a http module or handler. You might want to take a look at this question

How to Prevent PostBack Event Handler from Firing

I have a custom class (ServerSideValidator.vb) that validates user input on server side (it doesn't use any of the .NET built in validators, therefore Page.Validate() is not an option for me). I am calling the Validate() method on page.IsPostback event and the class performs without any problem
My issue is, when validation fails (returns false), I want to stop the postback event handler from firing, but load the page along with all the controls and user-input values in them. If I do, Response.End(), the page comes up blank. I can programmatically instruct the page to go to the previous page (original form before postback), but it loses all user-inputs.
I thought of creating a global boolean variable in the page code behind file and check the value before performing any postback method, but this approach takes away from my plan to provide all functionalities inside the class itself. The page object is being referenced to ServerSideValidator.
Seems like all the postback related properties/variables I come across inside Page class are 'Readonly' and I can't assign value(s) to control/prevent postback event from firing.
Any idiea on how I can accomplish this? Please let me know if you need further details
It's probably easier to post back to the same page every time and do your validation there, specifically on the page load event. If the validation fails, you're already on the correct page and don't have to go to a previous page. If the validation succeeds, then you can redirect to another page if you wish, in which case you probably don't need any data.
Edit: This isn't exactly what you asked for, but I have a feeling it will do what you want while fitting into the existing ASP.NET validation design. See http://www.dotnetcurry.com/ShowArticle.aspx?ID=197 and https://web.archive.org/web/20211020145934/https://www.4guysfromrolla.com/articles/073102-1.aspx
Basically, you create a custom class just like you have now, but inherit from BaseValidator. To follow your design, you can create an enum called ValidationType which has Alphabetic, Alphanumeric, etc. In your custom class, create a property called ValidationType that uses the ValidationType enum. Of course you have to add all the validation logic. Then in your aspx page, you can add your custom validator to the page and set ValidationType="Alphabetic", etc. with full IntelliSense support.
Since you use BaseValidator, all the regular validation techniques will work including Page.Validate(), Page.IsValid, etc. You can even create client-side validation JavaScript if you wish.
Having said this, someone has probably already done most of this for you.

Resources