The Orchard Dojo Library is a portable package of Orchard Core goodies. It supplements Orchard Dojo's trainings and tutorials. These are also part of the best practices and guidelines we use at Lombiq.
You can download the whole Library, file issues or fork it from its repository. Also you can download the Library's textual content as one big concatenated document in HTML.
When returning a collection, always return an empty collection if there are no elements, but never null. When accepting a collection as a method argument, however, always check for null.
```csharp
IEnumerable MyMethod(IEnumerable collection)
{
// Check for null and handle it somehow
if (collection == null) throw new ArgumentNullException("collection");
if (nothingToReturn) return Enumerable.Empty<int>();
else return normally;
}
```
Keep interfaces as short as possible so it’s relatively simple to provide alternative implementation for them (even when doing unit testing).
If a method would serve just as a shortcut for multiple method calls on the same interface, use extension methods. Whether or not to use an extension method should be decided on a case-by case basis as future-aware as possible: only use extension methods if the shortcut is (almost) trivial and add the method to the interface if the optimal solution is more likely to depend on the specific implementation.
```csharp
// Good example: the shortcut is simple
public interface IService
{
void Register(int id);
}
public static class ServiceExtensions
{
void Register(this IService service, DbEntity entity)
{
service.Register(entity.Id);
}
}
// Extensions are also useful if you want to provide default arguments for methods and want to do it with overloads
public interface IService
{
IEnumerable GetItems(int maxCount);
}
public static class ServiceExtensions
{
IEnumerable GetItems(this IService service)
{
// This extension provides a default value for the GetItems() method call
service.GetItems(15);
}
}
// Bad example: GetMany() results in many Get() calls. The implementation of GetMany() is something that the implementation of IService is likely to decide on better.
public interface IService
{
object Get(int id);
}
public static class ServiceExtensions
{
IEnumerable
Orchard best practices
Always do part shape-related heavy work in shape factories inside drivers: this way if the shape is not displayed (i.e. not specified in or hidden from Placement.info) no work will be done.
csharp
public override IDisplayResult Display(MyPart titlePart, BuildPartDisplayContext context)
{
return Initialize<MyPartViewModel>(GetDisplayShapeType(context), model =>
{
// This delegate will only run if the shape is actually displayed.
// Do heavy work here.
})
.Location("Detail", "Content:5");
}
When writing a theme if something is achievable by only CSS, then use only CSS and avoid having shape template overrides with minimal modifications. If you absolutely have to create shape overrides then try to override the most specific shape possible: e.g. if you need to override the markup of blogposts' title then override just BlogPost-Title (the shape responsible for showing the title) and not the whole Content shape.
If a template uses a static resource (stylesheet or script) always include/require it there even if the template is part of a bigger layout where those resources are already referenced. This makes it easier to keep track of dependent resources and is not prone to errors caused by changes outside the specific template.
For improving client-side performance by preventing blocking script loads always include scripts in the foot if they’re not required immediately on page load. Also consider using the async attribute on scripts if the order in which they’re executed is indifferent.
When you have multiple features in a single module always make the sub-features depend on the main feature for clarity. This will prevent confusion if you want to place some common functionality in the main feature. It should also be the requirement anyway: sub-features are in that module because they have something in common with the main feature.
Although not mandatory, it's good practice to route all your admin controller to under /Admin in a similar way how controllers named "AdminController" are routed by default. This makes it easier to set up rules for the admin area if one needs it.
Texts presented to the user should always be in form of LocalizedStrings (aka T[]). When you want to display dynamic data in the string, it should always have its parameters supplied to it. Never concatenate localized strings with other values as this prevents complete localization. E.g. if you want to display the number of elements use a printf-like pattern:
It's nice to have a consistent ordering for dependencies in module manifest files. A good way is to begin with third-party features, then list built-in ones (OrchardCore.*), both in alphabetical order.
When doing I/O-bound work, always use async APIs if available (e.g. web requests, file writes). Using async I/O greatly increases the throughput of the server by not blocking threads to wait for I/O completion.
When writing Migrations it's best to consolidate the latest schema in the Create method and only make UpdateFromX() run for existing installations. The Training Demo module has an example of how to do this.
Never do any non-trivial work (i.e. pretty much anything apart from variable assignments) in the constructors of injectable types. The dependency injection framework can instantiate your type any time, as the tree of dependencies can result in hundreds of instantiations happening when a type is resolved. Thus any work done in a constructor can possibly have a negative performance effect in seemingly unrelated cases.
If you want to produce a value for a field that won't change during the lifetime of the object then do this by lazily producing that value when its first accessed (e.g. with Lazy<T>) .
When you want to access a form field from JavaScript that was built with a statically typed Html helper for a view model property (like with Html.HiddenFor()) then never hard-code the field element's ID into your script: such generated IDs can change with the underlying implementation and by changing the editor prefix. Instead, populate such IDs from your templates, e.g. by passing the output of Html.IdFor() to the script.
When creating a new controller action don't forget to set the page title somewhere, best from the main view template of the action. I.e.:
```cshtml
@RenderTitleSegments(T["My Page"])
```
Or if you just want to update the content of the <title> tag directly (like it is necessary on admin pages, where the title is already displayed):
cshtml
@{
Title.AddSegment(T["My Page"]);
}
Note that generally it's bad practice to set the title from content part shape templates: those are meant to be a fragment of the layout so they shouldn't set the title directly; the title is to be set by a higher level component that actually knows what the whole page is about.
About displaying validation info in templates:
If you want to display the validation errors corresponding to a specific field, which is generally a good practice, then you can display it like this (you can use other elements than span):
html
<span asp-validation-for="MyField"></span>
Most of the time it's good practice to also, or instead display a validation summary on the top of the page, but close to the form:
cshtml
@Html.ValidationSummary()
Never display a validation summary from a content part editor for the same reason as not to set the page title (see above).
When creating ad-hoc shapes then (unless the shapes are very generic) prefix the shapes' names with the module's name (e.g. My_Company_My_Module_My_Shape). Shape names are global identifiers, so if they're only interesting for your module you have to use an appropriate name.
Remember authorization! When letting the user fetch content items by ID or otherwise in any way remember that a malicious user might try to trick your code into fetching content not intended to be shown. As a rule of thumb you should always authorize the user's access (through the IAuthorizationService service) to a content item object.
Never check the "Own" content permissions (like DeleteOwnContent) directly, just the generic ones (e.g. DeleteContent) as the former ones are handled internally by the latter ones.
When you have no choice but catching the base Exception then use the Exception.IsFatal() extension method to not deal with fatal exceptoins.
JavaScript best practices
Prefix jQuery objects with the dollar sign ($) so they can be distinguished from other objects.
var $header = $("#header");
Instead of using the $ variable directly use a wrapper to inject the jQuery object and only use the dollar sign in the local scope.
// The dollar sign will be used only inside the anonymous function here.
(($) => {
// The variable $ now refers to jQuery.
})(jQuery);
Add any DOM manipulation code and event handlers inside the document.ready() function to make sure the script does not try to find the elements before the DOM has finished loading. This is recommended by the official jQuery documentation.
// Notice how it's a shorthand for a wrapper for the $ variable (as above) and also a document.ready() at once.
// Use this if you only want to write a quick document.ready().
jQuery(($) => {
$('.elementClass').on('click', () => { // Click event handler.
alert('I have been clicked.');
});
});
Try to avoid adding variables to the global scope. A handy way of exposing globals is to namespace them under jQuery as demonstrated with the following example:
(($) => {
$.extend(true, {
myModule: {
// Such deep nesting is not always necessary, the method could be on this level directly
myClass: { // More of a "class" than a real class of course
myMethod() {
alert('myMethod called!');
},
},
},
});
// You can use the above like this:
$.myModule.myClass.myMethod();
})(jQuery);
When you want to access resources under a given URL of the current web application (like fetching data from a web API endpoint) never hard-code the URL into yours scripts. URLs can change and may depend on the environment (a trivial example being the usage of ApplicationPath that e.g. could prefix URL's during local development but can be empty in the production environment).
Instead inject such information into your scripts from templates.
CSS best practices
Use a language that eases CSS development and compiles into CSS like LESS or SASS. It's really worth trying! (And there's good tooling support.)
When something is possible to style in a straightforward way without the usage of images by only using CSS (even e.g. by using font icons), then do it from CSS.
Try to avoid HTML markup that serves just to enable some kind of styling.
For HTML classes and IDs use dashed names e.g. this-is-a-class. In Orchard modules you may prefix these with the module name.
Source control best practices
The following advice applies to the Git source control system.
Committing
Try to only include changes corresponding to a single task in a commit. Discrete changes should go into discrete changesets. Try to avoid having multiple logical changes in the same commit as this will make it difficult to back out of certain changes if necessary.
Push your commits often if you're working in a team.
Use descriptive commit messages.
Don't store assets (i.e. files generated from the source) in source control if possible, e.g. the bin and obj folder should be excluded.
Commit often if you have finished something. If you have something working, or a section done, commit it. It will make much easier to track changes instead of having one big changeset. If your code is not affecting anybody else's work (because you're working in your own branch that won't be merged for a while) then the only criterion a commit must meet is that it should compile properly. This is to encourage frequent commits. If your code change affects somebody else's work too then of course you should take more care and test it.
If your repository uses submodules: When you did some change to a submodule then always commit the submodule change into the main repo too in the end. The point is that everybody pulling the main repo will also get the current version of all submodules too. This doesn't mean that you have to make a main repo commit for each submodule commits (commits in the submodule can very well be more frequent), but once you're done with a batch of work, commit that to the main repo too. Because of the same reason never push to the submodule alone but rather push the main repo.
Branching
If you use an issue tracker then have issues open for every non-trivial task. Then, having issues created, somehow reference the issue from source control, like with conventional branch names.
If you use branches for developing features prefix the branch names with something and use a pattern like "feature/[branch name]" to make those branches distinguishable from other branches.
Try to avoid merging branches with themselves. If you committed to a branch locally but meanwhile somebody else did the same first then rebase instead.
When doing work in a branch separated from the main line of development merge frequently from the main branch. Frequent, small merges are easier and less error-prone than big merges and also you'll be able to integrate your changes with the work done by others.
Code styling
C# styling
If there length of the parameter list for a method is too long to read conveniently in terms of line length (due to the 3-argument rule this should rarely happen for methods but constructors with dependency injection) break it into multiple lines parameter by parameter.
csharp
public class MyClass
{
public MyClass(
IDependency1 dependency1,
IDependency2 dependency2,
IDependency3 dependency3)
{
// ...
}
}
Prefix private fields with an underscore (_).
Have a standard ordering of members depending on their visibility and whether they're instance- or class-level, etc.
Notice the order:
constant fields
readonly fields
other fields
properties
constructors
instance methods
static methods
inner classes
Within this order, fields and properties are sorted first by static vs. non-static, and inside each of these by private, protected, public.
Methods and inner classes are sorted public, protected, private.
```csharp
public class MyClass
{
// Constant fields come before everything else.
public const string MyConst = "const";
// Readonly fields should appear before non-readonly fields
private readonly string _myReadonly = "readonly";
// Static fields first
private static string _myStaticField = "field";
// Private fields
private string _myField = "field";
protected string _myProtected = "field";
// Properties next
public int MyProperty { get; set; }
// Then the constructor(s)
public MyClass()
{
}
// Public methods
public void MyMethod()
{
}
// Protected methods
protected void MyProtected()
{
}
// Private methods
private void MyPrivateMethod()
{
}
// Static methods
public static void MyPublicStaticMethod()
{
}
private static void MyStaticMethod()
{
}
// Inner classes
public class MyInnerClass
{
}
}
```
If an expression is short, omit line breaks when applicable to keep the code compact (as long as readability is not hurt), e.g.:
csharp
public class MyClass
{
private int _myField;
public int MyProperty { get { return _myField; } }
}
CSS styling
Structure your stylesheet's content logically under titles. Use the following comment formats for different levels of titles:
```css
/* First-level title
*********************/
// Second-level title
// -------------------------
/Third-level title/
```
Use line breaks to space out blocks of code.
Naming conventions
Use the suffix “Base” for abstract classes.
Suffix part classes) with "Part".
Name js and css files with the segments of their names delimited by dashes, e.g. my-style.css.
Resource names declared in resource manifests are also global so prefix them with the module's name e.g. "MyModule.MyStyle".
If the number of injected dependencies (services) exceeds 5
If the number of arguments for a method exceeds 3
It adds invaluable safety if you have unit tests for the code being refactored. If you don't have unit tests for a piece of code, before heavy refactoring is probably the good time to create them.
Try not to over-engineer things. A typical and simple to detect sign of an over-complicated system is if you have classes that are almost exclusively proxying calls to other classes.
Renaming a project
You should do the following steps to rename an existing .NET project (including an Orchard Core module or theme).
Make a backup or commit to source control before attempting the rename.
Rename the project from inside Visual Studio. This will change the project's name in a lot of manifest files.
Search and replace the project's name in all files of the project or even of the solution (if you project's name is not a unique text be careful). This will rename all namespaces too.
Rename the project's folder (if it has one) to match the project's names. You'll have to re-add the project file under its new location to the solution as well as to other projects' references (if any).
Inline documentation guidelines
Don’t overdo documentation as it can do more harm than use when going out of date, which it tends to do.
Always document complex pieces of logic by briefly explaining what the code does and why.
Always document unusual solutions, hacks or workarounds, and explain why they are necessary.
It's advised to document interfaces, best with usage samples. This is especially true for services: Always document services, as these are commonly used by other developers too.
Never use comments for mental notes (like "TODO"). Such notes should go into more appropriate places like an issue tracker, some common documentation or something else.
Documentation should be as close to what it documents as possible to avoid going out of date.
It's good to document what the aim of a type (mostly class or interface) is. This is to be able to quickly understand what a type does without having to understand its code.
Write documentation just like you write code: Use correct grammar and punctuation (remember that comments are sentences), adhere to style conventions.
C# keywords like true, referenced in XML comments, should be wrapped into a see element as follows: /// <returns><see langword="true"/> on success, <see langword="false"/> otherwise.</returns>
Generic types should be referenced as follows: <see cref="ILookup{TKey, TValue}"/>
As seen in the above examples, don't add a space before self-closing elements in XML comments. This is due to the way automatic tooling generates those elements, as it would be cumbersome to change every such instance.
Doing static code reviews is a great way to improve code quality and share knowledge in a team.
Read this study about code reviews at Cisco; lot of good tips there. Also, this article is an ideal and simple checklist that can be used for code review.
It's best to use a tool for code review where you can give comment for specific lines in the code. E.g. GitHub and Bitbucket both offer code line commenting for commits and pull requests. Unless the changes are trivial also open the source files in an IDE though, some issues stand out there better.
When doing code reviews, don't just look at the code lines but also try to understand the whole component you review pieces of. This way you can also give your opinion about higher-level architectural decisions.
If you want to optimize for a quick review turnaround then you can just look at the change from a user's perspective at first, i.e. you can try out the feature. Then, only when it works well, may you check out the code. Checking the code first and the UI only once you don't see any issues with the code can be a viable approach too.
Pay attention to pinpoint all kinds of issues: e.g. architectural, logical, styling, maintainability issues all count.
Don't just look at what's there but also think about what's missing (e.g. validation, error handling, access control...).
If you see repeated issues with the code (e.g. the same mistake repeated all over the code base) then don't add the same comment multiple times. Either reference the other locations in a single comment (e.g. "This is also repeated in the other controllers here.") or if you're reviewing a bigger piece of code then collect such issues in a shared document (or a comment for the whole codebase if you tool allows it) and just reference them (e.g. "See CodeReview.docx #3").
Development environment advice
Some advice on how to set up your development environment for Orchard Core development.
Software to install
Below you can find pieces of software that you should install for the best Orchard Core developer experience. Also check out the official documentation.
Visual Studio 2022 (any edition) or later installed with "ASP.NET and web development" tools and the following extensions:
Attach To All The Things for quickly attaching the debugger to an IIS (Express) and other processes. Debug Attach Manager is for a similar goal: If you select to attach a process for a given app then it'll remember it and select the suitable process the next time automatically, even after a VS restart (especially handy for .NET apps with their dotnet.exe processes). Similarly, ReAttach to quickly re-attach the debugger to previous debug targets.
An up-to-date browser with developer-aiding tools. Recommended is Chrome with the JavaScript Errors Notifier extension to get notified of client-side errors easily (it's a bit like the Orchard Error Log Watcher feature of the Lombiq Orchard Visual Studio Extension).
F11: step into the code on the current line (e.g. if the current line is a method call this will forward you to the body of the method), when debugging
Ctrl+Shift+Enter: adds a new line below the current line
F9: places a breakpoint on the current line
Ctrl+K, Ctrl+D: format document
Ctrl+K, Ctrl+C: comment selection
Ctrl+K, Ctrl+U: uncomment selection
Ctrl+,: opens the Navigate To windows (i.e. search for types or members)
Ctrl+D, Ctrl+E or Ctrl+Alt+E: opens the Exceptions configuration page. Tick Common Language Runtime Exceptions - Thrown to see all exceptions, even if they're caught.
Ctrl+Q to access the Quick Launch bar
Shift+Del: delete line
You may want to set up Ctrl+W for closing the current file for the File.Close command and Ctrl+Shift+T for Edit.UndoClose (only available if PowerCommands is installed).
You may want to always run VS as an administrator. This will simplify debugging web apps running in IIS since you can only attach a debugger to the IIS worker process if VS is run as an administrator.
To speed things up by not running a virus scan all the time on your development environment exclude the following processes from Windows Security: devenv.exe, dotnet.exe, MSBuild.exe, node.exe.
When you start the app with the debugger attached (i.e. with F5) then by default a new browser window will open, and if you move that under an existing window as a tab the debugger will detach. To mitigate this you need to uncheck Tools → Options → Projects and Solutions → Web Projects → "Stop debugger when browser window is closed, close browser when debugging stops".
Orchard performance optimization guidelines
Orchard performance checklist
When optimizing an Orchard Core site's performance (or just putting it into production) check these points for the most obvious ways for a boost.
Enable the Response Compression feature to gzip HTTP responses.
Cookie-less domain and/or CDN is used for static resources (including Media files).
When doing I/O tasks, use async APIs. Not blocking threads to wait for an I/O task to complete increases the throughput of the server.
If your application is under heavy load memory usage will inherently increase. If you have more than 4GB of memory and you're on a 64b machine don't be afraid to use a 64b application pool: this will also increase memory usage but the site will be able to use more than what is available for it from the 32b address space. You can set up an application pool to run a 64b worker process simply by setting "Enable 32-Bit Applications" to False (under advanced settings of the AppPool).
Disable IIS Logging or too chatty Failed Request Tracing.
Detecting performance bottlenecks
The built-in Mini Profiler module is an easy to use Orchard module for pinpointing (mostly DB-related) bottlenecks quickly, even on a production machine.
Orchard Core training guidelines
The following guidelines serve as a base for Orchard Core trainings and you're welcome to hold your own Orchard Core training using these guidelines.
During courses we routinely touch on various technologies and paradigms used by Orchard. The knowledge of these is thus an advantage though not a necessity, and participants will also have a chance to learn about them in practice. Here are some keywords of some technologies and paradigms used in Orchard Core:
Overall what we think is roughly what participants should already know about:
Mandatory: basic usage of Visual Studio, basic knowledge of C#, basic knowledge of client-side web development (HTML, CSS, JS), previous experience in building .NET (web) apps.
Strongly advised: basic understanding of Git or some other source control system, ASP.NET Core MVC, and strong knowledge of C#.
Advised: understanding inversion of control containers and dependency injection, usage of the Razor syntax for HTML templates.
Technical requirements
The following tools are needed for an Orchard training:
Administrative account to install other components if necessary and to avoid permission issues when running Orchard
Trainer's PC having all of the above and connected to a projector for demonstrations
A whiteboard or something similar
Topics
The topics are each divided into individual modules. These modules can, but don't necessarily have dependency on each other.
When conducting a training even before these start with an introduction of yourself, then of the participants to get a general feeling of where everybody is coming from, and what would be interesting for them. Note that the indicated time requirements are more like guidelines on the minimal recommended time. Allocate sufficient time above this for discussions, and in the case of multi-day trainings, for recaps at the beginning of each day.
Following are methodologies for various forms of Orchard Core trainings.
Remember that it's a good thing to have regular breaks within every hour.
Keep the time between explaining something new and demonstrating it short; i.e. if you explain something, show it.
After a session (lesson, tutorial video...) do a quick recap of what was covered: click through what was explained and briefly mention again if there is something to emphasize.
Utilize the Visual Studio snippets to write code quickly instead of typing out everything. Use the Utility Scripts to speed up common tasks like creating an Orchard Visual Studio solution.
We've created a demo module for the purpose of teaching all the topics here with well explained examples, the Orchard Training Demo module. The training topics loosely follow the Training Demo. If you want to use the Training Demo as a reference when giving a training, even copy-pasting from it then the Comment Remover Visual Studio extension can come handy: You can remove the Training Demo's comments so they're not clutter while you explain the same thing.
Suggest further resources and reading materials for attendees, e.g.:
Every lesson begins with a short warm-up task incorporating the topics of the previous lesson.
Lessons generally have repeated cycles of the following form:
Presentation: the course leader explains the current topic (10-15 minutes), if the content is practical (like doing some dashboard work) students follow individually
Group work
After hearing the presentation about how to solve a certain problem students are encouraged to try out the new techniques for given tasks in form of a group work. The task either
consists of the topic demonstrated before
or is something slightly new that can be derived from the demonstration or learned by reading a short documentation.
The former one is a good choice if there is enough time, the latter one is efficient if there's only limited time available.
Groups of 2-3-4 try to solve a problem while the course leader is helping their work and is available for questions
Evaluation of the group work: discussing common questions and issues
Examination
The course has no special examination, instead students should create and finish and Orchard-based web application project.
Students form teams of arbitrary size (it’s also possible to work alone)
Every team’s task is to create a real-world Orchard-based web application
There are no limitations or obligations to that, although the groups are encouraged to develop one custom module that uses existing Orchard features in a creative way but doesn’t replicate any built-in functionality
One student gives a presentation of the project after completing it with a maximal length of 5 minutes. The presentation should be a live demonstration of the web application. After the presentations the course leader has very brief code review sections with all of the other students were the students present a section of their software, demonstrating their understanding.
Schedule
Additional is the time needed for student presentations (depends on the number of attendees) since the course’s final lesson consists of student presentations and code reviews.
Intensive course
Since intensive courses should be tailored to the participants' needs the following points are just outlines and tips. Time constraint is also a factor that determines how in-depth the training can be, how many demonstrations can be carried out and how big is the part of the API that's only shown.
Live demonstration of the usage of Orchard APIs.
Live demonstration of some inner workings with t.he debugger (e.g. demonstrating how the tree of shapes is built up)
Showing aspects of the Orchard API without running them just so participants can get to know what piece of API to look for when they want to achieve something (e.g. IMediaFileStore is a good candidate: it's easy to use but one needs to know about it).
Few hour-long hackathon with a certain aim (e.g. to develop a module that's needed by the participants)
Code review: participants write some code on their own, then the trainer checks them and comments on them line by line with code review tools. Common mistakes can be discussed with the whole group.
If the course is online:
Record the sessions if the client would like it.
Break days can be added too, with no training taking place: That way participants can catch up with their daily activities, have a chance to digest what was learned, are encouraged to try out everything themselves, and come back with questions for the next occasion.
It's easier to keep the meeting running for short breaks. When participants come back they can signal that they're present with the "raise hand" feature many webmeeting tools have.
Demo: installing and basic settings. You can install with the Agency theme at this stage if you want to show differences between recipes or install with the Blog recipe right away to showcase its content types later.
Explaining the Manifest (BaseTheme), Startup class
Usual folders
Razor vs Liquid, tag helpers
Code generation templates
Shapes
Notion of shapes, hierarchical rendering of shapes (demonstrate it with the call stack using the debugger, e.g. with MenuItem.cshml, also explaining shape caching)
The notion and use of the Layout shape, checking it out with the debugger
Alternates and overrides (the basic ones and examples of others like for the menu). You can ovverride TitlePart.cshtml as an example.
Shape templates and important view variables (e.g. Context, Title, Model, User), T-strings
Writing editor and display shape templates, explaining Model object usage
Ad-hoc shapes
Static resources: styles/scripts (how to include/require them) and resource manifests
Parts and their comparison to entities, part data storage
Content type and content part migrations, code generation with Helpful Extensions
Drivers: Display and edit methods
Editor and display shapes
Handlers
Placement
Exercise
Module code generation
SpaceShip content type
Title part for name
AutoroutePart for url
SpaceShipPart content part
Captain
Class
Number of crew
MediaPickerField (needs the Fields feature) for an image: for this also a shape template override with a stylesheet include (e.g. the image should be displayed with rounded corners)
IShapeTableProvider implementation to add alternates (see e.g. OrchardCore.Contents.Shapes), wrappers (see e.g. MediaShapes), classes, hook into events
Shape methods with the Shape attribute (see DemoShapeProvider)
Lombiq .NET Analyzers: .NET code analyzers and code convention settings so you can see Orchard-style conventions and and best practices enforced in your IDE, as well as during build.
Visual Studio code snippets
You can use these code snippets to quickly generate code in some common scenarios during Orchard Core module and theme development. The snippets follow Orchard naming conventions. Check out this demo video for a quick overview of our snippets.
To effectively use this collection of VS snippets just point the Snippets Manager to where you cloned or downloaded this repository (https://github.com/Lombiq/Orchard-Dojo-Library). To do this go under Tools → Code Snippets Manager → select the C# language → Add and Add the whole folder. For Razor snippets to also work select the HTML Language and do the same. Do note that Razor snippets will only be suggested when you hit Ctrl + space first.
The snippets also automatically add the necessary namespaces.
We've taken care to place the $end$ terminating symbol to a place where one most possibly wants to follow up with coding. Thus if you exit snippets by hitting enter the cursor will be placed where you most likely want to write next.
These snippets are constantly used at Lombiq and updated according to our experiences.
General snippets
controller: Empty ASP.NET MVC controller class.
ctorinject: Constructor with an injected dependency and a corresponding private readonly field.
pbcon: Public constant field that returns its own name.
privr: Private readonly field.
propv: Virtual auto-implemented property.
servsc: Scoped service registration.
Orchard Core snippets
Orchard Core snippets are prefixed with "oc" for distinction.
ocstartup: Startup class for an extension's feature.
Orchard Dojo Library contribution guidelines
The Orchard Dojo Library is fully open source and can be edited by anyone. If you find an error or would like to improve it, you're more than welcome; just submit a pull request!
The Library is stored as Markdown-formatted text files in a repository on GitHub. The files can be edited with any text editor, but we recommend Notepad++, or VS Code which offers a live preview for Markdown files.
Name files and folders with PascalCasing.
Files named Index.md are automatically opened when requesting their folder.
You can use relative links to link between files; paths are the same online as they are in the repository. Keep in mind that links to folders (when the Index file is opened automatically) must end with a slash (/) while links to files shouldn't.
Add a line break after the title header (line starting with #); keep a line break after any sub-headings (line starting with two or more #).
When adding inline code snippets, use the `backtick-delimited syntax`.
When adding paths or filenames, emphasize (italicize) them like this: _C:\path\to\file.txt_ → C:\path\to\file.txt.
Don't include HTML elements in the Markdown files.
Encode HTML entities, e.g. use < and > for the < and > characters.
If you mention an XML or HTML element wrap it with backticks, e.g. <img>, so it's not misinterpreted as markup on the page.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.