Create Self installing widget from DLL
I'm hoping to get some help and guidance on how to create a DLL that self installs a widget into a toolbox in sitefinity. I don't want to create and install a module with widgets - just a single widget on it own, using the fluent API if that's possible?
I've seen a great blog post by Peter Marinov which shows how to achieve this when creating a module with a widget. I only want to install a single widget, without a module. Is this not possible?
My apologies in advance if I'm being a bit dumb, but I've not been able to figure out how to do it. Would really appreciate a big nudge in the right direction.
- Mark McNeece
No thats the perfect post to use...you don't need to do any of the module bits, just install your toolbox stuff. That's what I'm doing with my widget assembly right now. I'm not a module, but I can (and do) install a ConfigElement and Widgets and Layouts.
Like do whatever you want to in that event, as long as the DLL is in the bin folder Sitefinity will fire it :)
Hey Mark,
Maybe this blogpost can be of help. It contains also the source on GitHub that I created some time ago which covers your case, I think.
Best regards,
Daniel
Hi Daniel
I've downloaded the source from GitHub. I need to pour over it and see where it takes me. Hopefully I'll be able to figure out where I'm going wrong from this.
Thanks heaps!
- Mark
Hello all,
You can use the following approach to register your controls:
public
class
Installer
public
static
void
PreApplicationStart()
// With this method we subscribe for the Sitefinity Bootstrapper_Initialized event, which is fired after initialization of the Sitefinity application
Bootstrapper.Initialized += (
new
EventHandler<ExecutedEventArgs>(Installer.Bootstrapper_Initialized));
private
static
void
Bootstrapper_Initialized(
object
sender, ExecutedEventArgs e)
if
(e.CommandName !=
"RegisterRoutes"
|| !Bootstrapper.IsDataInitialized)
return
;
InstallWidget();
/// <summary>
/// Registering the widget using the fluent API
/// </summary>
private
static
void
InstallWidget()
RegisterControl(
"EcommerceDonations"
,
typeof
(DonationsWidget),
"PageControls"
,
"EcommerceDonations"
);
public
static
void
RegisterControl(
string
controlName, Type controlType,
string
toolboxName,
string
sectionName)
var configManager = ConfigManager.GetManager();
var config = configManager.GetSection<ToolboxesConfig>();
var controls = config.Toolboxes[toolboxName];
var section = controls.Sections.Where<ToolboxSection>(e => e.Name == sectionName).FirstOrDefault();
if
(section ==
null
)
section =
new
ToolboxSection(controls.Sections)
Name = sectionName,
Title = sectionName,
Description = sectionName,
ResourceClassId =
typeof
(PageResources).Name
;
controls.Sections.Add(section);
if
(!section.Tools.Any<ToolboxItem>(e => e.Name == controlName))
var tool =
new
ToolboxItem(section.Tools)
Name = controlName,
Title = controlName,
Description = controlName,
ControlType = controlType.AssemblyQualifiedName
;
section.Tools.Add(tool);
configManager.SaveSection(config);
Hi Nikola
Thanks for your input. I've got that part working. The toolbox section gets created and my widget gets added to it. I just can't get the widget designer to work. I'm slightly lost on getting that part working.
I've had a look through the example at the link Daniel gave above, but it's a bit complex and hard to follow. I'm afraid I need a "HelloWorld" type example on this. It's driving me nuts. I must be close to it, but there's something that's eluding me.
My work in progress class library is at the following dropbox link. Would be great if someone could show me where I'm going wrong and/or what else I need to do?
https://www.dropbox.com/s/w3win5zudbhtcpu/Breadcrumbs.zip?dl=0
Thanks :-)
Hi Mark,
Please, change the designer template and JavaScript to be embedded resource and reference them the following way:
public
static
readonly
string
layoutTemplatePath = Breadcrumbs.breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.ascx"
;
public
static
readonly
string
scriptReference = Breadcrumbs.breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.js"
;
[assembly: System.Web.UI.WebResource(
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.js"
,
"text/javascript"
)]
Thanks Nikola
I did those things, but still no joy. However, I no longer get an error when trying to edit the widget, but the designer isn't loading. I've updated the dropbox with my updated class library, which now includes your suggestions. Must be very close now?
https://www.dropbox.com/s/w3win5zudbhtcpu/Breadcrumbs.zip?dl=0
Hello,
The widget and the designer are working on my end. Here is a video (screencast.com/.../qdjPYJij) showing this. Please, ensure the resources are embedded, delete the widget section from the application, build and restart it. Could you please provide information on the error you receive? Is the script loaded?
Regards,
Nikola Zagorchev
Telerik
Hi Nikola
It's still not working for me unfortunately. I created a video showing me deleting everything from the sitefinitywebapp, then building it again, etc.
I've attached a screen capture with the chrome dev tools open showing that the designer script isn't being loaded.
Hi Mark,
I think you need to add the javascript file to the AssemblyInfo file like this:
[assembly: System.Web.UI.WebResource(
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.js"
,
"application/x-javascript"
)]
Or decorate your designer class (aka: BreadcrumbsDesigner.cs) with the following code:
using
System;
using
System.Linq;
using
System.Web.UI;
using
Telerik.Sitefinity.Web.UI;
using
Telerik.Sitefinity.Web.UI.ControlDesign;
using
System.Collections.Generic;
[assembly: WebResource(Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.js,
"application/x-javascript"
)]
namespace
Breadcrumbs.Widgets.Breadcrumb.Designer
---
Either way will work.
Let me know if that solved your problem?
Best regards,
Daniel Plomp
Ah, you already added the line to the AssemblyInfo file. I missed that.
I also noticed that this line of code:
private
readonly
string
breadcrumbWidgetTemplatePath = breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumbs.breadcrumbs.ascx"
;
... probably needs to be like this:
private
readonly
string
breadcrumbWidgetTemplatePath = breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumb.breadcrumbs.ascx"
;
Since there is no Breadcrumbs folder under the Widget directory. It is named Breadcrumbs with an extra 's', so you need to strip that.
Maybe that is causing the error.
Best regards,
Daniel
Well spotted Daniel - but I'm sorry to say it's made no difference. Still got the exact same problem when I try to edit the widget.
Weird problem!?
I always delete the reference to the project from my Sitefinity installation. Then I delete the /Debug and /Release folder under the projects /bin folder and also delete the hidden /obj folder. After that rebuild and re-add the project as a reference.
Maybe that does do the trick?
Best,
Danie.
You've got one more cleanup step there than me - I'll try that right now... brb! ;-)
No joy I'm afraid. Exactly the same as before. Screen grab attached.
That is so strange. Is that dropbox link still the actual source? I don't want to ask, but you're sure that the .js and .ascx files are embedded into the project?
Best,
Daniel
I've just now updated the dropbox with the latest version of my class library - as I have indeed tweaked things here and there. Yes, the .js and .ascx files are definitely set as embedded resources.
Can you try to update this code inside the BreadcrumbsDesigner.cs file:
#region Private members & constants
public
static
readonly
string
layoutTemplatePath = Breadcrumbs.breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.ascx"
;
public
static
readonly
string
scriptReference = Breadcrumbs.breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.js"
;
#endregion
... to this:
#region Private members & constants
public
static
readonly
string
layoutTemplatePath = Breadcrumbs.breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.ascx"
;
public
static
readonly
string
scriptReference =
"Breadcrumbs.Widgets.Breadcrumb.Designer.BreadcrumbsDesigner.js"
;
#endregion
As I don't think the virtual path is needed to reference the script file.
Best,
Daniel
I tried it - exactly the same result I'm afraid.
Hi Mark,
I think I've found the problem. When you add a ScriptReference to the ScriptReference collection that is inserted into the javascript file, you also need to give the assembly name. Here you see the GetScriptReferences code:
public
override
IEnumerable<ScriptReference> GetScriptReferences()
var scripts =
new
List<ScriptReference>(
base
.GetScriptReferences());
// Get the assembly name
var assemblyName = GetType().Assembly.GetName().ToString();
scripts.Add(
new
ScriptReference(scriptReference, assemblyName));
return
scripts;
I think you need to change this in your project and also remove the virtual path from the ScriptReference, as stated in my previous post.
Let me know how that works out for you?
I needed to do the total cleanup, before it worked :)
Best,
Daniel
OMG! ... OMG!!
"Daniel Plomp for World President!"
Your an absolute mega star!! My computer very nearly er... "fell down the stairs", and I was fast losing the will to live. I'm a bit confused how Nikola got it to work then? Maybe she added that and forgot to mention it?
Um... I now want to add an embedded style sheet. Is there any I should know to achieve that, or should I be able to figure it out from what I have now?
Thank you again so much, and to everyone that helped me!!
- Mark
Hey Mark,
Glad you got it to work! Great news.
Regarding the stylesheet: you should indeed add this also to your project as an
embedded resource and also to your AssemblyInfo file or to your Breadcrumbs.ascx.cs:
[assembly: WebResource(STYLE_REFERENCE_PATH_WITHOUT_VIRTUAL_PATH,
"text/css"
)]
namespace
Breadcrumbs.Widgets.Breadcrumb
...
Then inside your Page_Load or Page_Init (not sure which one) you can add the stylesheet like this:
// Include our stylesheet
const
string
includeTemplate =
"<link rel='stylesheet' text='text/css' href='0' />"
;
var includeLocation =
Page.ClientScript.GetWebResourceUrl(
typeof
(BreadCrumbs), STYLE_REFERENCE_PATH_WITHOUT_VIRTUAL_PATH);
var include =
new
LiteralControl(String.Format(includeTemplate, includeLocation));
Page.Header.Controls.Add(include);
Because the stylesheet also is an embedded resource now, you have to include it like this.
Best,
Daniel
Thanks Daniel!
I added the code add the stylesheet to the onPreRender event and got it working. Page_Load and Page_Init didn't work.
protected
override
void
OnPreRender(EventArgs e)
// Include our stylesheet
const
string
includeTemplate =
"<link rel='stylesheet' text='text/css' href='0' />"
;
var includeLocation = Page.ClientScript.GetWebResourceUrl(
typeof
(Breadcrumbs), stylesheetReference);
var include =
new
LiteralControl(String.Format(includeTemplate, includeLocation));
Page.Header.Controls.Add(include);
base
.OnPreRender(e);
public
static
readonly
string
breadcrumbWidgetVirtualPath =
"~/BreadcrumbWidget/"
;
private
readonly
string
breadcrumbWidgetTemplatePath = breadcrumbWidgetVirtualPath +
"Breadcrumbs.Widgets.Breadcrumb.breadcrumbs.ascx"
;
public
readonly
string
stylesheetReference =
"Breadcrumbs.Widgets.Breadcrumb.Styles.breadcrumbs.css"
;
This has been an invaluable exercise indeed!! Many, many thanks again!!
Very best,
Mark
Hi,
I was actually referenced the script correclty from the assembly but have forgotten to mention it. Please, excuse me for that. All resources used in external widget should be embedded, so they could be loaded from the widget assembly. They should be loaded as a WebResources (WebResource.axd). This could be done through the script manager or using the ResourceLinks widget, as described here, so we can ensure the resources are loaded only once. The resource links widget could load embedded and not embedded scripts.
Regards,
Nikola Zagorchev
Telerik
Hi
Did the issue got resolved ?? If yes please provide me the solution as I am getting the same problem.
Hello
The problem was with the script reference. It was not loading the javascript file needed for the control.
Regards,
Nikola Zagorchev
Telerik
Hi Daniel,
I hope you are doing well. I have a question on how to install a single module on its own. Can you please help me how to install module automatically(self installing module).
Thanks,
Balu
Hello Balu,
What module you would like to create and install?
You can take a look at the Sitefinity STS Integration sample, since it shows a separate installing module with a widget and other resources:
https://github.com/Sitefinity/Sitefinity-External-STS-Integration
Regards,
Nikola Zagorchev
Telerik
I could create and install the module in the Sitefinity
project. The registered module is not listed under content however It was listed under Administrator-->settings-->Modules and services.
Can you please help me the following queries?
How can I create child pages for the module
through coding??
Hi Balu,
If you import a Dynamic Module built using the Module Builder, the backend pages will be created automatically.
Note that if you are in Multisite, you need to add the module for the sites you want, so it creates a provider for that module and shows under Content page.
Regards,
Nikola Zagorchev
Telerik