I need to hook into the Creating event in Orchard CMS and use the Title of the content that's being created (Along with some other properties) to create an item in a 3rd party system and return the ID of that to set in the content type in Orchard.
I have a custom content type, but when I try to hook into the events (as explained in the docs here and also by looking at code on the built in Orchard Core content parts) all properties are null.
Are they just lazy loaded? Is there a way to populate them? Overriding any of the shape methods (GetItemMetadata / BuildDisplayShape / BuildEditorShape / UpdateEditorShape) doesn't seem right as this should only fire when initially creating the content type.
My code is:
public MyContentPartHandler(IRepository<MyContentPartRecord> repository, IOrchardServices orchardServices, Lazy<IMyContentPartService> myContentPartService) {
_orchardServices = orchardServices;
_myContentPartService = myContentPartService;
Filters.Add(StorageFilter.For(repository));
OnCreating<MyContentPart>(CreateTPItemAndAssignIdentity);
}
protected void CreateTPItemAndAssignIdentity(CreateContentContext context, MyContentPart part)
{
//create item in 3rd party system
var item = _myContentPartService.Value.CreateNewItem(part.Title, part.Path);
part.ExternalIdentity = item.FriendlyId;
}
The CreateNewItem() method fails as the part.Title and part.Path are null. Do I need to try and get at the Record? (I thought not, as the Orchard CMS record has not been created at that point)
UPDATE - I have also tried to use the OnCreated event instead, but I run into the same problem with the properties not being populated. I place a breakpoint in the code, and noticed that when the OnCreated breakpoint was hit - the data did not actually exist in the database at that time.
OnCreating/OnCreated events are fired when an item object is constructed, not populated with data.
If you want to be sure that data is already there, use either OnPublished event (fired after item has been updated) or OnLoading/OnLoaded events if you want to run some code after an item has been fully loaded from database.
This description of certain events might also be helpful.
Related
I have tried finding an answer to this question practically everywhere I could imagine, including here on StackOverflow. Unfortunately to no avail. So here it is.
I'm working on an Outlook Add-in (with Outlook 2021), and have developed some code that creates some ItemProperties specifically for use with that add-in. Now, when those properties are created, I can see them when I go to View->Settings->Advanced View Settings->Columns, as illustrated in the screenshot.
Screenshot of User-defined fields in Outlook
In some cases, though, I want to completely delete the properties. And as I know how to do that manually, as pointed out in the figure, I can't find out how to do that programmatically via C#. I have gone that far as to remove the properties from each mail containing that kind of property, like this:
IEnumerable<MailItem> listOfAssignedEmails = itemsToProcess.Where(
t => t.ItemProperties[MailExpiration.ExpirationDatePropertyName] != null);
foreach (MailItem email in listOfAssignedEmails)
{
// Note: The Delete() operation is deprecated. A more up-to-date method must be found.
email.ItemProperties[MailExpiration.ExpirationDatePropertyName].Delete();
email.Save();
}
... and yes, I know that the Delete() operation is deprecated; however, I couldn't find another method for removing the ItemProperty from the email (any suggestions are welcome).
Basically, the deletion of this Property is only going to be done very rarely (t. ex. if the user chooses to uninstall the Add-in. However, if there's any way to remove that property automatically, I would be happy to know.
Any suggestions will be greatly appreciated.
It is really a bad idea to remove a custom property from all emails that already have it: there is really no point since the user will never see them, but you will have to retouch (and thus change the last modified date) of a large number of emails.
Also note that named properties in MAPI are a finite resource - you can have at most 64k of them in a mailbox. Once a particular property mapping is used, you can never unmap it, even if there are no items that use that property.
Thirdly, doing anything Outlook related from an installer (rather than a VSTO addin) is a really bad idea - Windows installer runs in a service.
If you want to make sure the user no longer sees your custom fields as available properties in a view, you need to deal with the folder fields - they ar stored in a blob in a hidden (associated) message in that folder. OOM does not expose folder fields at all (if you don't count the AddToFolderFields parameter when calling UserProperties.Add). If using Redemption is an option (I am its author), it exposed RDOFolderFields object (accessible from RDOFolder2.FolderFields property) that allows to add or delete folder fields.
The list of properties shown on the screenshot belongs to the Folder.UserDefinedProperties property which returns a UserDefinedProperties object that represents the user-defined custom properties for the Folder object.
Use the ItemProperties.Remove method removes an object from the collection (from an item).
Use the ItemProperties property to return the ItemProperties collection. Use ItemProperties.Item(index), where index is the name of the object or the numeric position of the item within the collection, to return a single ItemProperty object.
On a SharePoint 2010 site, I have an ItemAdded event receiver which detects pages added to the Pages library, fills it with information from a file, and from that information sets some custom columns so that the pages can be searched based on their contents. The portion of the function that sets the columns is similar to this:
page.SetProperty("Column1", ExistsOrEmpty("Property1", dictionary));
page.SetProperty("Column2", ExistsOrEmpty("Property2", dictionary));
...
page.Update();
Where page is of type SPFile and is the page that has been added to the library. ExistsOrEmpty is a function I wrote to prevent a KeyNotFound exception:
private static string ExistsOrEmpty(string key, Dictionary<string, string> dict)
{
try
{
return dict[key];
}
catch
{
return "";
}
}
My issue is that there is one column in particular, Description, that isn't updated on the site, even though the rest are updated without any problems. Here are the steps I've taken to debug this code when stepping through line by line:
I make sure ExistsOrEmpty("Description", dict) returns the correct value, which it does.
I execute page.SetProperty("Description", ExistsOrEmpty("Description", dict)), along with all of the other properties I wish to set. All of the properties I update are single-line strings.
I update the page using page.Update().
I check the page's properties using page.GetProperty to confirm that all properties have been updated correctly, which they have.
I finish debugging and check the page's properties on the SharePoint site itself using View Properties. All the properties I've set except the Description have been updated.
I can't imagine why this one column wouldn't update when the others have updated without a problem. Am I missing something?
EDIT: I've done some tweaking to try to fix this issue, and it has begun happening for multiple other columns as well. I noticed that, for the other columns, the error occurs where the column name used to have a space and I removed it. I've made sure to update my code to account for these changes, and my debugger still shows the columns as being updated, but the UI does not reflect these changes. Using internal names rather than display names fixed this problem, but not the main problem I'm having with the Description.
Can you try this please.
Your SPFile object should have an SPListItem object on it.
it will be something like page.item["Description"] = "desc"
Then call an update.
Cheers
Truez
I'm trying to do something my teacher says can't be done; I would like to prove him wrong.
In the CreateChildControls method of my SharePoint 2010 webpart, I am referencing a User Control file called "ChartUserControl.ascx" in my project that contains the ASP.NET code for a WebChartControl object configured just the way I want it. WebChartControl has an ID of "OrderQtyChart".
What I want to do is take the code from that UserControl and use it create a new WebChartControl, called "chart", with matching configuration. I'm trying to do this because there are callbacks etc. that need to be performed on the chart after it's created to actually populate it with chart-stuff.
So, my code:
WebChartControl chart;
protected override void CreateChildControls()
{
ChartUserControl userControl = new ChartUserControl();
// referencing file ChartUserControl.ascx as an object
chart = userControl.FindControl("OrderQtyChart") as WebChartControl;
// or
chart = (WebChartControl)userControl.FindControl("OrderQtyChart");
// Trying to tell the code to create 'chart' using the code defined in object
"OrderQtyChart" located in ChartUserControl.ascx
}
Or something like that. In either instance above, 'chart' will return null.
I'm trying to use the front end code of OrderQtyChart as a template for 'chart'; they're both the same type of object and I don't get any errors until I try to create 'chart' on my page, at which point I'm told it's null.
Is there a way to do this? It would save me a ton of time not to have to configure 'chart' completely at creation time. Even if I have to reference my front-end code for OrderQtyChart a different way.
Thanks.
[Edited 7/9 for clarity]
What you are trying to do seems very well possible and I assume your teacher did not understand your question correctly. Here are a few tips on how this is done:
Object A could be one of these:
A visual control such as label or textbox. In this case your will have to traverse the visual controls from parent to child by doing direct parent.FindControl("ObjectA");
It is an instance of a class. This might be a MyClass or a new textbox that is created by code. In this case you'll have to create a public property that has a getter which returns ObjectA. although you can use FindControl in case ObjectA is a UI component that is created and added dynamically at run-time. Otherwise, you'll have to stick with property.
FindControl will not traverse the parent to child hierarchy, so you'll have to do a recursive method in order to successfully find the ObjectA or if you have access to its direct parent, call FindControl on that. More info here: http://geekswithblogs.net/QuandaryPhase/archive/2009/05/06/asp.net-recursive-findcontrol-amp-extension-methods.aspx
Page life cycle plays an important role here, so make sure that you keep it in mind or you'll end up with a null reference that is not really caused by FindControl
Gah, never mind. I realized I can just call the user control directly and I'm seriously overcomplicating this.
That's a whole new question, so I'll just start a different thread.
I'm currently looking for a solution to my issue: In our ASP.NET MVC application there are pages that are used for realtime data visualization of industrial devices. When the page gets loaded, a loading icon is shown while I fetch the viewmodel data with the current values for all the datapoints from a database. That works quite well, but it is static, by which I mean that the values don't change on the page after it finished loading. The web application itself uses a TCP listener that receives messages with values from the devices. These messages (which basically consist of a device id, a datapoint id and the value) don't arrive in fixed intervals but event-based, e.g. when a temperature value changes 0.5 K up or down.
On my page I have some graphical widgets like gauges and many other elements that correctly show the values from the initial data that gets loaded on the page load. They are bound to the Knockout viewmodel.
The problem is this: whenever a new value arrives on the server, I want to show it on the page without the need for a reload. I definitely don't want to re-transmit the whole viewmodel with some hundred datapoints on every message that arrives on the server (appr. 1 to 15 per second). In order to achieve that, I implemented the SignalR framework, which really works great. With that mechanism I now receive the new value in the client window (that means, I receive it in Javascript and now have a value object like described below).
What I need now is this: as every viewmodel gets built dynamically, they are all different. The object and properties tree is not the same for two devices, so each of them can have varying levels of subobjects. The only thing that is the same is the structure of the object that actually holds the value for each datapoint: it always consists of the aforementioned device id, the datapoint id and the value.
I need a way to update the double-type value inside the value object within the viewmodel whose device id and datapoint id match the newly arrived value message (that also consists of these two address-like ID's and the value).
I hope I got the idea across. Is there a way to do this? What would be the best practice for such a mechanism? I recently switched to Knockout-MVC (kMVC nuget package), but I'd also go back to "pure" Knockout.js and some additional scripting if that helps.
Thanks for your help and recommendations!
http://nthdegree.azurewebsites.net/mvvm-2/
Here is an article speaking to the Knockout mapping plugin
The general idea is that you should have your view model code which loads your model.
You would bind up your view model which will have a property you load from the server with an ajax call (see bottom of article).
You then just update the model with the result with
ko.mapping.fromJS(newData, mapping, modelToUpdate)
var mapping = {}; //define your mapping (see documentation or blog post)
function ViewModel(){
var self = this;
self.model = ko.mapping.fromJS({}, mapping);
self.hub = $.connection.myHub();
self.hub.client.updateModel = function(data){
ko.mapping.fromJS(data, mapping, self.model);
};
self.hub.start().done(function(){
//you could either make a call or have the "OnConnected" method trigger an 'updateModel'
});
}
ViewModel properties when linked to a DOM element allows editing which is actually updating the data in the KO observable array. Is it possible for you to change the "graphical widget"'s value (assuming that it is using some property to maintain height and width) using the IDs which you said are consistent?
I have not tested; the other option is to use KO foreach loop and update the related value.
I am writing custom property for umbraco that counts hits on document.
Is there any way how can I hook up my logic to page when document is loading?
Example:
I have structure:
Home
About me
Both have my custom Property.
I would like to record when they have been loaded.
Note: I do not want to use any javascript, or actions on page. I would like to have it as one custom DLL.
Solution that I have chosen is:
use IHttpModule as umbraco does not have any event that can be used for this.
As to configuration:
I have decided dynamicaly hook up my module after application start.
Thnx all for considering my question.
One way to do it would to have a separate db table specifically for page hits, e.g. [PageHit] which had two columns [NodeId] and [HitCount].
A hit on a page either created a new record if no hits had previously been recorded, or incremented the count on an existing record.
You would need to ensure that the hit was recorded per page, so recording it in the your base Masterpage or in a base Controller would be my approach.
You could then have a property based upon a custom datatype that looked up the hit count for the specific node that the property existed upon. The custom datatype could be a usercontrol, and since in the Umbraco backoffice when you load a node in the content editor the node's ID is in the query of the URL, you can access this in the usercontrol to query the database.
Using a separate table allows you to separate things into a separate DLL too as you would not need to be reliant on the Umbraco API as you could use an ORM like PetaPoco or basic ADO.
I certainly wouldn't write directly back to the node itself as this would cause an unnecessary load on the database, causing latency on the site's page loads and generally slow things down.
If you want to keep this data inside the Umbraco backend, you'd need to create an usercontrol and embed that control in the masterpage (top masterpage);
In the usercontrol add these usings:
using umbraco.cms.businesslogic.web;
using umbraco.BusinessLogic;
using umbraco.presentation.nodeFactory;
And a method similar to this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack) // don't want to count postbacks
{
Document nodeCount = new Document(Node.GetCurrent().Id);
int Count = 0;
try
{
Count = Convert.ToInt32(nodeCount.getProperty("hitCount").Value);
}
catch
{
Count = 0; // value == null, not set yet
}
nodeCount.getProperty("hitCount").Value = Count + 1;
nodeCount.Save();
nodeCount.Publish(new User(0));
umbraco.library.UpdateDocumentCache(nodeCount.Id);
}
PS this is written without testing.. just of the top of my head