Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26c148dccc | |||
| 8497056185 | |||
| 5498e2c2bb | |||
| 602a8ce08c | |||
| 7e82524c4e | |||
| 783973b9da | |||
| 096cd1ef73 | |||
| 07b01fa318 | |||
| 0ba253c61d | |||
| 5da7f034e9 | |||
| 8eebd4ccae | |||
| c47e254efe | |||
| 3f35749619 |
@@ -27,11 +27,4 @@ dotnet_naming_symbols.private_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
|
||||
|
||||
dotnet_naming_style.prefix_underscore.capitalization = camel_case
|
||||
dotnet_naming_style.prefix_underscore.required_prefix = _
|
||||
|
||||
# https://github.com/MicrosoftDocs/visualstudio-docs/blob/master/docs/ide/editorconfig-code-style-settings-reference.md
|
||||
[*.cs]
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_prefer_braces = false : none
|
||||
dotnet_naming_style.prefix_underscore.required_prefix = _
|
||||
@@ -1,66 +0,0 @@
|
||||
---
|
||||
name: 🐛 Bug Report
|
||||
about: File a bug report, if you've discovered a problem in Umbraco.
|
||||
---
|
||||
|
||||
A brief description of the issue goes here.
|
||||
|
||||
<!--
|
||||
|
||||
If you haven't yet done so, please read the "contributing guidelines"
|
||||
thoroughly. Then, proceed by filling out the rest of the details in the issue
|
||||
template below. The more details you can give us, the easier it will be for us
|
||||
to determine the cause of a problem.
|
||||
|
||||
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
|
||||
|
||||
-->
|
||||
|
||||
|
||||
|
||||
Reproduction
|
||||
------------
|
||||
|
||||
If you're filing a bug, please describe how to reproduce it. Include as much
|
||||
relevant information as possible, such as:
|
||||
|
||||
### Bug summary
|
||||
|
||||
<!--
|
||||
* Write a short summary of the bug
|
||||
* Try to pinpoint it as much as possible
|
||||
* Try to state the _actual problem_, and not just what you _think_ the
|
||||
solution might be.
|
||||
-->
|
||||
|
||||
### Specifics
|
||||
|
||||
<!--
|
||||
* Mention the URL where this bug occurs, if applicable
|
||||
* What version of Umbraco are you using (down to the very last digit!)
|
||||
* What browser and version you are using
|
||||
* Please mention if you've checked it in other browsers as well
|
||||
* Please include *full error messages* and *screenshots* if possible
|
||||
-->
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
<!--
|
||||
* Clearly mention the steps to reproduce the bug
|
||||
-->
|
||||
|
||||
### Expected result
|
||||
|
||||
<!--
|
||||
* What did you _expect_ that would happen on your Umbraco site?
|
||||
* Describe the intended/desired outcome after you did the steps mentioned.
|
||||
-->
|
||||
|
||||
### Actual result
|
||||
|
||||
<!--
|
||||
* What is the actual result of the above steps?
|
||||
* Describe the behaviour of the bug
|
||||
* Please, please include **error messages** and screenshots. They might mean
|
||||
nothing to you, but they are _very_ helpful to us.
|
||||
-->
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
name: 📮 Feature Request
|
||||
about: Open a feature request, if you want to propose a new feature.
|
||||
---
|
||||
|
||||
A brief description of your feature request goes here.
|
||||
|
||||
|
||||
<!--
|
||||
If you want to discuss the feature you're imagining, please make sure to keep
|
||||
those discussions on the forum at https://our.umbraco.com/ (choose the
|
||||
category "Contributing to Umbraco", Umbraco HQ follows all new topics there).
|
||||
|
||||
Once you've come to a conclusion in the discussion, feel free to propose the
|
||||
new feature here.
|
||||
-->
|
||||
|
||||
How can you help?
|
||||
-------------------------------
|
||||
|
||||
<!--
|
||||
The resources (read: available time and effort) of Umbraco's core team are
|
||||
limited.
|
||||
|
||||
If we can not work on your suggestion, please don't take it personally. Most
|
||||
likely, it's either:
|
||||
|
||||
- We think your idea is valid, but we can't find the time to work on it.
|
||||
- Your idea might be better suited as a package, if it's not suitable for
|
||||
the majority of users.
|
||||
-->
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
name: ⁉️ Support Question
|
||||
about: Having trouble with Umbraco? -> https://our.umbraco.com
|
||||
---
|
||||
|
||||
This issue tracker is NOT meant for support questions. If you have a question,
|
||||
please join us on the forum at https://our.umbraco.com.
|
||||
|
||||
Thanks!
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
name: 📖 Documentation Issue
|
||||
about: See https://github.com/umbraco/UmbracoDocs/issues for documentation issues
|
||||
---
|
||||
|
||||
The Umbraco documentation has its own dedicated repository. Please open your
|
||||
documentation-related issue at https://github.com/umbraco/UmbracoDocs/issues
|
||||
|
||||
Thanks!
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
name: 🔐 Security Issue
|
||||
about: Discovered a Security Issue in Umbraco?
|
||||
---
|
||||
|
||||
⚠️ PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
|
||||
|
||||
If you have found a security issue in Umbraco, please send the details to
|
||||
security@umbraco.com and don't disclose it publicly until we can provide a fix for
|
||||
it. If you wish, we'll credit you for finding verified issues, when we release
|
||||
the patched version.
|
||||
|
||||
❗ Please read more about how to report security issues on https://umbraco.com/security
|
||||
|
||||
A note on "Self XSS"
|
||||
--------------------
|
||||
|
||||
Umbraco is a CMS, that allows users to edit content on a website. As such,
|
||||
all _authenticated users_ can:
|
||||
|
||||
- Edit content, and (depending on the field types) insert HTML and CSS in that
|
||||
content, with a variety of allowed attributes.
|
||||
- Depending on the user level: Edit template files, and insert C#, HTML, CSS and
|
||||
javascript in so on.
|
||||
- Upload files to the site, which will become publicly available.
|
||||
|
||||
We see these functionalities as _features_, and not as security issues. Please
|
||||
report the mentioned items only if they can be performed by non-authorized
|
||||
users, or other exploitable vulnerabilities.
|
||||
|
||||
Thanks!
|
||||
@@ -1,12 +0,0 @@
|
||||
### Prerequisites
|
||||
|
||||
- [ ] I have added steps to test this contribution in the description below
|
||||
|
||||
If there's an existing issue for this PR then this fixes: <!-- link to the issue here! -->
|
||||
|
||||
### Description
|
||||
<!-- A description of the changes proposed in the pull-request and how to test these changes -->
|
||||
|
||||
|
||||
|
||||
<!-- Thanks for contributing to Umbraco CMS! -->
|
||||
@@ -1,61 +0,0 @@
|
||||
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
|
||||
|
||||
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS) to go to the v7 branch._
|
||||
|
||||
_Ready to try out Version 8? [See the quick start guide](V8_GETTING_STARTED.md)._
|
||||
|
||||
When is Umbraco 8 coming?
|
||||
=========================
|
||||
When it's ready. We're done with the major parts of the architecture work and are focusing on three seperate tracks to prepare Umbraco 8 for release:
|
||||
1) Editor Track (_currently in progress_). Without editors, there's no market for Umbraco. So we want to make sure that Umbraco 8 is full of love for editors.
|
||||
2) Partner Track. Without anyone implementing Umbraco, there's nothing for editors to update. So we want to make sure that Umbraco 8 is a joy to implement
|
||||
3) Contributor Track. Without our fabulous ecosystem of both individual Umbracians and 3rd party ISVs, Umbraco wouldn't be as rich a platform as it is today. We want to make sure that it's easy, straight forward and as backwards-compatible as possible to create packages for Umbraco
|
||||
|
||||
Once a track is done, we start releasing previews where we ask people to test the features we believe are ready. While the testing is going on and we gather feedback, we move on to the next track. This doesn't mean that there hasn't already been work done in the area, but that a track focuses on finalizing, polishing and preparing the features for release.
|
||||
|
||||
Umbraco CMS
|
||||
===========
|
||||
The friendliest, most flexible and fastest growing ASP.NET CMS, and used by more than 443,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
|
||||
|
||||
[](https://vimeo.com/172382998/)
|
||||
|
||||
## Umbraco CMS
|
||||
Umbraco is a free open source Content Management System built on the ASP.NET platform. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social.
|
||||
|
||||
## Watch an introduction video
|
||||
|
||||
[](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/)
|
||||
|
||||
## Umbraco - The Friendly CMS
|
||||
|
||||
For the first time on the Microsoft platform, there is a free user- and developer-friendly CMS that makes it quick and easy to create websites - and a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, right out of the box.
|
||||
|
||||
Umbraco is not only loved by developers, but is a content editor's dream. Enjoy intuitive editing tools, media management, responsive views, and approval workflows to send your content live.
|
||||
|
||||
Used by more than 443,000 active websites including Carlsberg, Segway, Amazon and Heinz and **The Official ASP.NET and IIS.NET website from Microsoft** ([https://asp.net](https://asp.net) / [https://iis.net](https://iis.net)), you can be sure that the technology is proven, stable and scalable. Backed by the team at Umbraco HQ, and supported by a dedicated community of over 220,000 craftspeople globally, you can trust that Umbraco is a safe choice and is here to stay.
|
||||
|
||||
To view more examples, please visit [https://umbraco.com/case-studies-testimonials/](https://umbraco.com/case-studies-testimonials/)
|
||||
|
||||
## Why Open Source?
|
||||
As an Open Source platform, Umbraco is more than just a CMS. We are transparent with our roadmap for future versions, our incremental sprint planning notes are publicly accessible, and community contributions and packages are available for all to use.
|
||||
|
||||
## Trying out Umbraco CMS
|
||||
|
||||
[Umbraco Cloud](https://umbraco.com/cloud) is the easiest and fastest way to use Umbraco yet, with full support for all your custom .NET code and integrations. You're up and running in less than a minute, and your life will be made easier with automated upgrades and a built-in deployment engine. We offer a free 14-day trial, no credit card needed.
|
||||
|
||||
If you want to DIY, you can [download Umbraco](https://our.umbraco.com/download) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
|
||||
|
||||
## Community
|
||||
|
||||
Our friendly community is available 24/7 at the community hub we call ["Our Umbraco"](https://our.umbraco.com). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
|
||||
|
||||
## Contribute to Umbraco
|
||||
|
||||
Umbraco is contribution-focused and community-driven. If you want to contribute back to Umbraco, please check out our [guide to contributing](CONTRIBUTING.md).
|
||||
|
||||
## Found a bug?
|
||||
|
||||
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](CONTRIBUTING_DETAILED.md#reporting-bugs).
|
||||
|
||||
You can comment and report issues on the [github issue tracker](https://github.com/umbraco/Umbraco-CMS/issues).
|
||||
Since [September 2018](https://umbraco.com/blog/a-second-take-on-umbraco-issue-tracker-hello-github-issues/), the old issue tracker is in read-only mode, but can still be found at [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
@@ -107,7 +107,6 @@ src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
|
||||
src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/
|
||||
|
||||
src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
|
||||
src/Umbraco.Web.UI.Client/vwd.webinfo
|
||||
|
||||
src/Umbraco.Web.UI/App_Plugins/*
|
||||
src/*.psess
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The MIT License (MIT) #
|
||||
|
||||
Copyright (c) 2013-present Umbraco
|
||||
Copyright (c) 2013 Umbraco
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@@ -1,56 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata minClientVersion="3.4.4">
|
||||
<id>UmbracoCms.Core</id>
|
||||
<version>8.0.0</version>
|
||||
<title>Umbraco Cms Core Binaries</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
|
||||
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<!--
|
||||
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
|
||||
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
|
||||
not want this to happen as the alpha of the next major is, really, the next major already.
|
||||
-->
|
||||
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
|
||||
<dependency id="LightInject" version="[5.1.2,5.999999)" />
|
||||
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
|
||||
<dependency id="LightInject.Web" version="[2.0.0,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Core" version="[2.2.2,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.Client" version="[5.2.6,5.999999)" />
|
||||
<dependency id="Microsoft.Owin" version="[4.0.0,4.999999)" />
|
||||
<dependency id="MiniProfiler" version="[3.2.0.157,3.999999)" />
|
||||
<dependency id="MySql.Data" version="[6.10.7,6.999999)" />
|
||||
<dependency id="Newtonsoft.Json" version="[11.0.2,11.999999)" />
|
||||
<dependency id="Semver" version="[2.0.4,2.999999)" />
|
||||
<dependency id="Serilog" version="[2.7.1,2.999999)" />
|
||||
<dependency id="Serilog.Enrichers.Process" version="[2.0.1,2.999999)" />
|
||||
<dependency id="Serilog.Enrichers.Thread" version="[3.0.0,3.999999)" />
|
||||
<dependency id="Serilog.Filters.Expressions" version="[2.0.0,2.999999)" />
|
||||
<dependency id="Serilog.Formatting.Compact" version="[1.0.0,1.999999)" />
|
||||
<dependency id="Serilog.Settings.AppSettings" version="[2.2.2,2.999999)" />
|
||||
<dependency id="Serilog.Sinks.File" version="[4.0.0,4.999999)" />
|
||||
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
|
||||
<dependency id="NPoco" version="[3.9.4,3.999999)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<!-- libs -->
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
|
||||
<metadata minClientVersion="3.4.4">
|
||||
<id>UmbracoCms.Core</id>
|
||||
<version>8.0.0</version>
|
||||
<title>Umbraco Cms Core Binaries</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
|
||||
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<!--
|
||||
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
|
||||
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
|
||||
not want this to happen as the alpha of the next major is, really, the next major already.
|
||||
-->
|
||||
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
|
||||
<dependency id="ClientDependency" version="[1.9.6,1.999999)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
|
||||
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
|
||||
<dependency id="Examine" version="[1.0.0-beta025,1.999999)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.7.2,1.999999)" />
|
||||
<dependency id="ImageProcessor" version="[2.6.1.19,2.999999)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.9.2.19,4.999999)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
|
||||
<dependency id="LightInject" version="[5.1.2,5.999999)" />
|
||||
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
|
||||
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
|
||||
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
|
||||
<dependency id="log4net" version="[2.0.8,2.999999)" />
|
||||
<dependency id="Log4Net.Async" version="[2.0.4,2.999999)" />
|
||||
<dependency id="Lucene.Net.Contrib" version="[3.0.3,3.999999)" />
|
||||
<dependency id="Markdown" version="[2.2.1,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.6,5.999999)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.6,5.999999)" />
|
||||
<dependency id="Microsoft.CodeAnalysis.CSharp" version="[2.8.0,2.999999)" />
|
||||
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[1.0.8,1.999999)" />
|
||||
<dependency id="Microsoft.Net.Compilers" version="[2.8.0,2.999999)" />
|
||||
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[4.0.0,4.999999)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[4.0.0,4.999999)" />
|
||||
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.0,4.999999)" />
|
||||
<dependency id="Microsoft.Web.Xdt" version="[2.1.2,2.999999)" />
|
||||
<dependency id="MiniProfiler" version="[3.2.0.157,3.999999)" />
|
||||
<dependency id="MySql.Data" version="[6.10.7,6.999999)" />
|
||||
<dependency id="Newtonsoft.Json" version="[11.0.2,11.999999)" />
|
||||
<dependency id="NPoco" version="[3.9.3,3.999999)" />
|
||||
<dependency id="Semver" version="[2.0.4,2.999999)" />
|
||||
<dependency id="System.Reflection.Primitives" version="[4.3.0,4.999999)" />
|
||||
<dependency id="System.Runtime.Handles" version="[4.3.0,4.999999)" />
|
||||
<dependency id="System.Security.Cryptography.X509Certificates" version="[4.3.2,4.999999)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.8.0,4.999999)" />
|
||||
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
|
||||
|
||||
<!-- docs -->
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
|
||||
<!-- docs -->
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
|
||||
</files>
|
||||
<file src="tools\install.core.ps1" target="tools\install.ps1" />
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Web.UI.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Web.UI\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata minClientVersion="3.4.4">
|
||||
<id>UmbracoCms.Web</id>
|
||||
<version>8.0.0</version>
|
||||
<title>Umbraco Cms Core Binaries</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Contains the web assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
|
||||
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<!--
|
||||
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
|
||||
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
|
||||
not want this to happen as the alpha of the next major is, really, the next major already.
|
||||
-->
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
|
||||
<dependency id="ClientDependency" version="[1.9.7,1.999999)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
|
||||
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
|
||||
<dependency id="Examine" version="[1.0.0-beta067,1.999999)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.8.9,1.999999)" />
|
||||
<dependency id="ImageProcessor" version="[2.6.2.25,2.999999)" />
|
||||
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
|
||||
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
|
||||
<dependency id="Markdown" version="[2.2.1,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.2,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.6,5.999999)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3,2.999999)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.6,5.999999)" />
|
||||
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[4.0.0,4.999999)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[4.0.0,4.999999)" />
|
||||
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.0,4.999999)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.8.0,4.999999)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<!-- libs -->
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
|
||||
|
||||
<!-- docs -->
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -1,65 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata minClientVersion="3.4.4">
|
||||
<id>UmbracoCms</id>
|
||||
<version>8.0.0</version>
|
||||
<title>Umbraco Cms</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
|
||||
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Web" version="[$version$]" />
|
||||
<!--
|
||||
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
|
||||
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
|
||||
not want this to happen as the alpha of the next major is, really, the next major already.
|
||||
-->
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
|
||||
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.29]" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.9.3.25,4.999999)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
|
||||
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.1,2.999999)" />
|
||||
<dependency id="Microsoft.Net.Compilers" version="[2.10.0,2.999999)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<!-- files -->
|
||||
<file src="$BuildTmp$\Configs\**" target="Content\Config" exclude="$BuildTmp$\Configs\Web.config.transform" />
|
||||
<file src="$BuildTmp$\WebApp\Views\**" target="Content\Views" exclude="$BuildTmp$\WebApp\Views\Web.config" />
|
||||
<file src="$BuildTmp$\WebApp\default.aspx" target="Content\default.aspx" />
|
||||
<file src="$BuildTmp$\WebApp\Global.asax" target="Content\Global.asax" />
|
||||
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
|
||||
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
|
||||
<metadata minClientVersion="3.4.4">
|
||||
<id>UmbracoCms</id>
|
||||
<version>8.0.0</version>
|
||||
<title>Umbraco Cms</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
|
||||
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<!--
|
||||
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
|
||||
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
|
||||
not want this to happen as the alpha of the next major is, really, the next major already.
|
||||
-->
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
|
||||
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.20]" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="$BuildTmp$\Configs\**" target="Content\Config" exclude="$BuildTmp$\Configs\Web.config.transform" />
|
||||
<file src="$BuildTmp$\WebApp\Views\**" target="Content\Views" exclude="$BuildTmp$\WebApp\Views\Web.config" />
|
||||
<file src="$BuildTmp$\WebApp\default.aspx" target="Content\default.aspx" />
|
||||
<file src="$BuildTmp$\WebApp\Global.asax" target="Content\Global.asax" />
|
||||
<file src="$BuildTmp$\WebApp\Web.config" target="UmbracoFiles\Web.config" />
|
||||
<file src="$BuildTmp$\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
|
||||
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
|
||||
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
|
||||
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
|
||||
<file src="$BuildTmp$\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
|
||||
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
|
||||
|
||||
<!-- these files are copied by install.ps1 -->
|
||||
<file src="$BuildTmp$\WebApp\Web.config" target="UmbracoFiles\Web.config" />
|
||||
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
|
||||
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
|
||||
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.htm" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.htm" />
|
||||
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.controller.js" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.controller.js" />
|
||||
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.resource.js" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.resource.js" />
|
||||
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\package.manifest" target="Content\App_Plugins\ModelsBuilder\package.manifest" />
|
||||
|
||||
<!-- tools -->
|
||||
<!-- beware! install.ps1 not supported by PackageReference -->
|
||||
<file src="tools\install.ps1" target="tools\install.ps1" />
|
||||
<file src="tools\Readme.txt" target="tools\Readme.txt" />
|
||||
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
|
||||
<file src="tools\install.ps1" target="tools\install.ps1" />
|
||||
<file src="tools\Readme.txt" target="tools\Readme.txt" />
|
||||
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
|
||||
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
|
||||
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
|
||||
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
|
||||
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
|
||||
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
|
||||
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
|
||||
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
|
||||
|
||||
<!-- config transforms -->
|
||||
<!-- beware! config transforms not supported by PackageReference -->
|
||||
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
|
||||
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
|
||||
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
|
||||
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
|
||||
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
|
||||
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
|
||||
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" /> <!-- FIXME Content\ !! and then... transform?! -->
|
||||
|
||||
<!-- UmbracoCms props and targets -->
|
||||
<file src="build\**" target="build" />
|
||||
</files>
|
||||
<file src="build\**" target="build" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
<CustomFilesToInclude Include=".\umbraco\**\*">
|
||||
<Dir>umbraco</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\umbraco_client\**\*">
|
||||
<Dir>umbraco_client</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\Global.asax">
|
||||
<Dir>.</Dir>
|
||||
</CustomFilesToInclude>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<section alias="StartupSettingsDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
|
||||
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
<tab caption="Welcome" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
|
||||
<control panelCaption="" xdt:Transform="InsertIfMissing">
|
||||
<control showOnce="true" addPanel="true" panelCaption="" xdt:Transform="InsertIfMissing">
|
||||
views/dashboard/settings/settingsdashboardintro.html
|
||||
</control>
|
||||
</tab>
|
||||
@@ -14,7 +14,7 @@
|
||||
<area>forms</area>
|
||||
</areas>
|
||||
<tab caption="Install Umbraco Forms">
|
||||
<control panelCaption="">
|
||||
<control showOnce="true" addPanel="true" panelCaption="">
|
||||
views/dashboard/forms/formsdashboardintro.html
|
||||
</control>
|
||||
</tab>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<section alias="StartupDeveloperDashboardSection">
|
||||
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Replace">
|
||||
<control panelCaption="">
|
||||
<control showOnce="true" addPanel="true" panelCaption="">
|
||||
views/dashboard/developer/developerdashboardvideos.html
|
||||
</control>
|
||||
</tab>
|
||||
@@ -47,7 +47,7 @@
|
||||
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
<tab caption="Content" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing" />
|
||||
<tab caption="Content" xdt:Locator="Match(caption)" xdt:Transform="Replace">
|
||||
<control panelCaption="">
|
||||
<control showOnce="false" addPanel="false" panelCaption="">
|
||||
views/dashboard/media/mediafolderbrowser.html
|
||||
</control>
|
||||
</tab>
|
||||
@@ -56,7 +56,7 @@
|
||||
<section alias="StartupMemberDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
|
||||
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
<tab caption="Get Started" xdt:Transform="Insert">
|
||||
<control panelCaption="">
|
||||
<control showOnce="true" addPanel="true" panelCaption="">
|
||||
views/dashboard/members/membersdashboardvideos.html
|
||||
</control>
|
||||
</tab>
|
||||
@@ -92,4 +92,4 @@
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
</dashBoard>
|
||||
</dashBoard>
|
||||
@@ -1,26 +1,26 @@
|
||||
|
||||
_ _ __ __ ____ _____ _____ ____
|
||||
| | | | \/ | _ \| __ \ /\ / ____/ __ \
|
||||
_ _ __ __ ____ _____ _____ ____
|
||||
| | | | \/ | _ \| __ \ /\ / ____/ __ \
|
||||
| | | | \ / | |_) | |__) | / \ | | | | | |
|
||||
| | | | |\/| | _ <| _ / / /\ \| | | | | |
|
||||
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
|
||||
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
|
||||
|
||||
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
|
||||
|
||||
----------------------------------------------------
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
|
||||
file (and config files in the config folder).
|
||||
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
|
||||
file (and config files in the config folder).
|
||||
|
||||
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
|
||||
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
|
||||
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
|
||||
Publish this won't affect you.
|
||||
The following items will now be automatically included when creating a deploy package or publishing to the file
|
||||
system: umbraco, config\splashes and global.asax.
|
||||
The following items will now be automatically included when creating a deploy package or publishing to the file
|
||||
system: umbraco, umbraco_client, config\splashes and global.asax.
|
||||
|
||||
Please read the release notes on our.umbraco.com:
|
||||
https://our.umbraco.com/download/releases
|
||||
http://our.umbraco.com/contribute/releases
|
||||
|
||||
- Umbraco
|
||||
- Umbraco
|
||||
@@ -1,30 +1,39 @@
|
||||
|
||||
_ _ __ __ ____ _____ _____ ____
|
||||
| | | | \/ | _ \| __ \ /\ / ____/ __ \
|
||||
_ _ __ __ ____ _____ _____ ____
|
||||
| | | | \/ | _ \| __ \ /\ / ____/ __ \
|
||||
| | | | \ / | |_) | |__) | / \ | | | | | |
|
||||
| | | | |\/| | _ <| _ / / /\ \| | | | | |
|
||||
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
|
||||
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
|
||||
|
||||
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
|
||||
|
||||
----------------------------------------------------
|
||||
|
||||
*** IMPORTANT NOTICE FOR UPGRADES FROM VERSIONS BELOW 7.7.0 ***
|
||||
|
||||
Be sure to read the version specific upgrade information before proceeding:
|
||||
https://our.umbraco.com/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-7-0
|
||||
|
||||
Depending on the version you are upgrading from, you may need to make some changes to your web.config
|
||||
and you will need to be aware of the breaking changes listed there to see if these affect your installation.
|
||||
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
We've done our best to transform your configuration files but in case something is not quite right: remember we
|
||||
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
|
||||
|
||||
We've overwritten all the files in the Umbraco folder, these have been backed up in
|
||||
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
|
||||
a package might have added. Only the existing files were overwritten. If you customized anything then make
|
||||
We've overwritten all the files in the Umbraco and Umbraco_Client folder, these have been backed up in
|
||||
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
|
||||
a package might have added. Only the existing files were overwritten. If you customized anything then make
|
||||
sure to do a compare and merge with the NuGetBackup folder.
|
||||
|
||||
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
|
||||
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
|
||||
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
|
||||
Publish this won't affect you.
|
||||
The following items will now be automatically included when creating a deploy package or publishing to the file
|
||||
system: umbraco, config\splashes and global.asax.
|
||||
The following items will now be automatically included when creating a deploy package or publishing to the file
|
||||
system: umbraco, umbraco_client, config\splashes and global.asax.
|
||||
|
||||
Please read the release notes on our.umbraco.com:
|
||||
http://our.umbraco.com/contribute/releases
|
||||
|
||||
- Umbraco
|
||||
- Umbraco
|
||||
@@ -150,6 +150,10 @@
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<applications xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<add alias="content" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="media" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="settings" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="developer" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="users" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="member" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="forms" name="Forms" sortOrder="6" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing" />
|
||||
<add alias="translation" sortOrder="7" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon,sortOrder)" />
|
||||
</applications>
|
||||
<add alias="content" icon="traycontent" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="media" icon="traymedia" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="settings" icon="traysettings" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="developer" icon="traydeveloper" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="users" icon="trayusers" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="member" icon="traymember" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
|
||||
<add alias="forms" name="Forms" icon="icon-umb-contour" sortOrder="6" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing" />
|
||||
<add alias="translation" icon="traytranslation" sortOrder="7" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon,sortOrder)" />
|
||||
</applications>
|
||||
@@ -33,6 +33,7 @@ if ($project) {
|
||||
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
|
||||
|
||||
# Delete files Umbraco ships with
|
||||
if(Test-Path $umbracoBinFolder\log4net.dll) { Remove-Item $umbracoBinFolder\log4net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }
|
||||
|
||||
@@ -44,6 +44,14 @@ if ($project) {
|
||||
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
|
||||
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientFolder
|
||||
$umbracoClientFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco_Client"
|
||||
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
|
||||
$copyWebconfig = $true
|
||||
$destinationWebConfig = Join-Path $projectPath "Web.config"
|
||||
|
||||
@@ -77,7 +85,15 @@ if ($project) {
|
||||
$splashesDestination = Join-Path $projectPath "Config\splashes\"
|
||||
New-Item $splashesDestination -Type directory
|
||||
Copy-Item $splashesSource $splashesDestination -Force
|
||||
|
||||
|
||||
$sqlCe64Source = Join-Path $installPath "UmbracoFiles\bin\amd64\*"
|
||||
$sqlCe64Destination = Join-Path $projectPath "bin\amd64\"
|
||||
Copy-Item $sqlCe64Source $sqlCe64Destination -Force
|
||||
|
||||
$sqlCex86Source = Join-Path $installPath "UmbracoFiles\bin\x86\*"
|
||||
$sqlCex86Destination = Join-Path $projectPath "bin\x86\"
|
||||
Copy-Item $sqlCex86source $sqlCex86Destination -Force
|
||||
|
||||
$umbracoUIXMLSource = Join-Path $installPath "UmbracoFiles\Umbraco\Config\Create\UI.xml"
|
||||
$umbracoUIXMLDestination = Join-Path $projectPath "Umbraco\Config\Create\UI.xml"
|
||||
Copy-Item $umbracoUIXMLSource $umbracoUIXMLDestination -Force
|
||||
@@ -143,4 +159,4 @@ if ($project) {
|
||||
{
|
||||
$DTE.ItemOperations.OpenFile($toolsPath + '\ReadmeUpgrade.txt')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,14 @@
|
||||
|
||||
$release = "" + $semver.Major + "." + $semver.Minor + "." + $semver.Patch
|
||||
|
||||
Write-Host "Update UmbracoVersion.cs"
|
||||
$this.ReplaceFileText("$($this.SolutionRoot)\src\Umbraco.Core\Configuration\UmbracoVersion.cs", `
|
||||
"(\d+)\.(\d+)\.(\d+)(.(\d+))?", `
|
||||
"$release")
|
||||
$this.ReplaceFileText("$($this.SolutionRoot)\src\Umbraco.Core\Configuration\UmbracoVersion.cs", `
|
||||
"CurrentComment => `"(.+)`"", `
|
||||
"CurrentComment => `"$($semver.PreRelease)`"")
|
||||
|
||||
Write-Host "Update IIS Express port in csproj"
|
||||
$updater = New-Object "Umbraco.Build.ExpressPortUpdater"
|
||||
$csproj = "$($this.SolutionRoot)\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj"
|
||||
@@ -61,9 +69,6 @@
|
||||
$global:node_nodepath = $this.ClearEnvVar("NODEPATH")
|
||||
$global:node_npmcache = $this.ClearEnvVar("NPM_CONFIG_CACHE")
|
||||
$global:node_npmprefix = $this.ClearEnvVar("NPM_CONFIG_PREFIX")
|
||||
|
||||
# https://github.com/gruntjs/grunt-contrib-connect/issues/235
|
||||
$this.SetEnvVar("NODE_NO_HTTP2", "1")
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("RestoreNode",
|
||||
@@ -73,8 +78,6 @@
|
||||
$this.SetEnvVar("NODEPATH", $node_nodepath)
|
||||
$this.SetEnvVar("NPM_CONFIG_CACHE", $node_npmcache)
|
||||
$this.SetEnvVar("NPM_CONFIG_PREFIX", $node_npmprefix)
|
||||
|
||||
$ignore = $this.ClearEnvVar("NODE_NO_HTTP2")
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("CompileBelle",
|
||||
@@ -92,40 +95,48 @@
|
||||
# so we have to take care of it else they'll bubble and kill the build
|
||||
if ($error.Count -gt 0) { return }
|
||||
|
||||
try {
|
||||
Push-Location "$($this.SolutionRoot)\src\Umbraco.Web.UI.Client"
|
||||
Write-Output "" > $log
|
||||
Push-Location "$($this.SolutionRoot)\src\Umbraco.Web.UI.Client"
|
||||
Write-Output "" > $log
|
||||
|
||||
Write-Output "### node version is:" > $log
|
||||
node -v >> $log 2>&1
|
||||
if (-not $?) { throw "Failed to report node version." }
|
||||
Write-Output "### node version is:" > $log
|
||||
&node -v >> $log 2>&1
|
||||
if (-not $?) { throw "Failed to report node version." }
|
||||
|
||||
Write-Output "### npm version is:" >> $log 2>&1
|
||||
npm -v >> $log 2>&1
|
||||
if (-not $?) { throw "Failed to report npm version." }
|
||||
Write-Output "### npm version is:" >> $log 2>&1
|
||||
&npm -v >> $log 2>&1
|
||||
if (-not $?) { throw "Failed to report npm version." }
|
||||
|
||||
Write-Output "### clean npm cache" >> $log 2>&1
|
||||
npm cache clean --force >> $log 2>&1
|
||||
$error.Clear() # that one can fail 'cos security bug - ignore
|
||||
Write-Output "### clean npm cache" >> $log 2>&1
|
||||
&npm cache clean --force >> $log 2>&1
|
||||
$error.Clear() # that one can fail 'cos security bug - ignore
|
||||
|
||||
Write-Output "### npm install" >> $log 2>&1
|
||||
npm install >> $log 2>&1
|
||||
Write-Output ">> $? $($error.Count)" >> $log 2>&1
|
||||
# Don't really care about the messages from npm install making us think there are errors
|
||||
$error.Clear()
|
||||
Write-Output "### npm install" >> $log 2>&1
|
||||
&npm install >> $log 2>&1
|
||||
Write-Output ">> $? $($error.Count)" >> $log 2>&1
|
||||
|
||||
Write-Output "### gulp build for version $($this.Version.Release)" >> $log 2>&1
|
||||
npx gulp build --buildversion=$this.Version.Release >> $log 2>&1
|
||||
if (-not $?) { throw "Failed to build" } # that one is expected to work
|
||||
} finally {
|
||||
Pop-Location
|
||||
Write-Output "### install bower" >> $log 2>&1
|
||||
&npm install -g bower >> $log 2>&1
|
||||
$error.Clear() # that one fails 'cos bower is deprecated - ignore
|
||||
|
||||
# fixme - should we filter the log to find errors?
|
||||
#get-content .\build.tmp\belle.log | %{ if ($_ -match "build") { write $_}}
|
||||
Write-Output "### install gulp" >> $log 2>&1
|
||||
&npm install -g gulp >> $log 2>&1
|
||||
$error.Clear() # that one fails 'cos deprecated stuff - ignore
|
||||
|
||||
# restore
|
||||
$this.RestoreNode()
|
||||
}
|
||||
Write-Output "### install gulp-cli" >> $log 2>&1
|
||||
&npm install -g gulp-cli --quiet >> $log 2>&1
|
||||
if (-not $?) { throw "Failed to install gulp-cli" } # that one is expected to work
|
||||
|
||||
Write-Output "### gulp build for version $($this.Version.Release)" >> $log 2>&1
|
||||
&gulp build --buildversion=$this.Version.Release >> $log 2>&1
|
||||
if (-not $?) { throw "Failed to build" } # that one is expected to work
|
||||
|
||||
Pop-Location
|
||||
|
||||
# fixme - should we filter the log to find errors?
|
||||
#get-content .\build.tmp\belle.log | %{ if ($_ -match "build") { write $_}}
|
||||
|
||||
# restore
|
||||
$this.RestoreNode()
|
||||
|
||||
# setting node_modules folder to hidden
|
||||
# used to prevent VS13 from crashing on it while loading the websites project
|
||||
@@ -388,15 +399,9 @@
|
||||
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
|
||||
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Core." }
|
||||
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Web.nuspec" `
|
||||
-Properties BuildTmp="$($this.BuildTemp)" `
|
||||
-Version "$($this.Version.Semver.ToString())" `
|
||||
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
|
||||
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Web." }
|
||||
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.nuspec" `
|
||||
-Properties BuildTmp="$($this.BuildTemp)" `
|
||||
-Version "$($this.Version.Semver.ToString())" `
|
||||
-Version $this.Version.Semver.ToString() `
|
||||
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cms.log"
|
||||
if (-not $?) { throw "Failed to pack NuGet UmbracoCms." }
|
||||
|
||||
@@ -412,7 +417,7 @@
|
||||
$ubuild.DefineMethod("VerifyNuGet",
|
||||
{
|
||||
$this.VerifyNuGetConsistency(
|
||||
("UmbracoCms", "UmbracoCms.Core", "UmbracoCms.Web"),
|
||||
("UmbracoCms", "UmbracoCms.Core"),
|
||||
("Umbraco.Core", "Umbraco.Web", "Umbraco.Web.UI", "Umbraco.Examine"))
|
||||
if ($this.OnError()) { return }
|
||||
})
|
||||
@@ -452,20 +457,6 @@
|
||||
if ($this.OnError()) { return }
|
||||
$this.PrepareAzureGallery()
|
||||
if ($this.OnError()) { return }
|
||||
$this.PostPackageHook()
|
||||
if ($this.OnError()) { return }
|
||||
Write-Host "Done"
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("PostPackageHook",
|
||||
{
|
||||
# run hook
|
||||
if ($this.HasMethod("PostPackage"))
|
||||
{
|
||||
Write-Host "Run PostPackage hook"
|
||||
$this.PostPackage();
|
||||
if (-not $?) { throw "Failed to run hook." }
|
||||
}
|
||||
})
|
||||
|
||||
# ################################################################
|
||||
@@ -481,4 +472,5 @@
|
||||
$ubuild.Build()
|
||||
if ($ubuild.OnError()) { return }
|
||||
}
|
||||
Write-Host "Done"
|
||||
if ($get) { return $ubuild }
|
||||
|
||||
@@ -17,7 +17,7 @@ Assume positive intent and try to understand before being understood.
|
||||
|
||||
Treat others as you would like to be treated.
|
||||
|
||||
This also goes for treating the HQ with respect. For example: don’t promote products on [our.umbraco.com](https://our.umbraco.com) that directly compete with our commercial offerings which enables us to work for a sustainable Umbraco.
|
||||
This also goes for treating the HQ with respect. For example: don’t promote products on [our.umbraco.org](https://our.umbraco.org) that directly compete with our commercial offerings which enables us to work for a sustainable Umbraco.
|
||||
|
||||
## Open
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/temp8/.github/V8_GETTING_STARTED.md) to go to the v8 branch_
|
||||
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/temp8/docs/CONTRIBUTING.md) to go to the v8 branch_
|
||||
# Contributing to Umbraco CMS
|
||||
|
||||
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
|
||||
@@ -16,9 +16,9 @@ This document gives you a quick overview on how to get started, we will link to
|
||||
|
||||
## Guidelines for contributions we welcome
|
||||
|
||||
Not all changes are wanted, so on occassion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valuable time.
|
||||
Not all changes are wanted so on occassion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valueable time.
|
||||
|
||||
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes.
|
||||
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md), make sure to talk to us before making large changes.
|
||||
|
||||
Remember, if an issue is in the `Up for grabs` list or you've asked for some feedback before you sent us a PR, your PR will not be closed as unwanted.
|
||||
|
||||
@@ -36,7 +36,7 @@ Great question! The short version goes like this:
|
||||
|
||||
* **Build** - build your fork of Umbraco locally as described in [building Umbraco from source code](BUILD.md)
|
||||
* **Change** - make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback](#questions)
|
||||
* **Commit** - done? Yay! 🎉 It is recommended to create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `12345`
|
||||
* **Commit** - done? Yay! 🎉 It is recommended to create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-U4-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `U4-12345`
|
||||
* **Push** - great, now you can push the changes up to your fork on GitHub
|
||||
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
|
||||
|
||||
@@ -72,6 +72,7 @@ The pull request team consists of a member of Umbraco HQ, [Sebastiaan](https://g
|
||||
- [Anders Bjerner](https://github.com/abjerner)
|
||||
- [Dave Woestenborghs](https://github.com/dawoe)
|
||||
- [Emma Burstow](https://github.com/emmaburstow)
|
||||
- [Kyle Weems](https://github.com/cssquirrel)
|
||||
- [Poornima Nayar](https://github.com/poornimanayar)
|
||||
|
||||
These wonderful volunteers will provide you with a first reply to your PR, review and test out your changes and might ask more questions. After that they'll let Umbraco HQ know if everything seems okay.
|
||||
@@ -81,7 +82,8 @@ These wonderful volunteers will provide you with a first reply to your PR, revie
|
||||
You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love open conversations and we are a friendly bunch. No question you have is stupid. Any questions you have usually helps out multiple people with the same question. Ask away:
|
||||
|
||||
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.org/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
|
||||
- We're also [active in the Gitter chatroom](https://gitter.im/umbraco/Umbraco-CMS)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
@@ -19,19 +19,19 @@ When contributing code to Umbraco there's plenty of things you'll want to know,
|
||||
* [What branch should I target for my contributions?](#what-branch-should-i-target-for-my-contributions)
|
||||
* [Building Umbraco from source code](#building-umbraco-from-source-code)
|
||||
* [Keeping your Umbraco fork in sync with the main repository](#keeping-your-umbraco-fork-in-sync-with-the-main-repository)
|
||||
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
### Reporting Bugs
|
||||
This section guides you through submitting a bug report for Umbraco CMS. Following these guidelines helps maintainers and the community understand your report 📝, reproduce the behavior 💻 💻, and find related reports 🔎.
|
||||
|
||||
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](https://github.com/umbraco/Umbraco-CMS/issues/new/choose), the information it asks for helps us resolve issues faster.
|
||||
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](http://issues.umbraco.org/issues#newissue=61-30118), the information it asks for helps us resolve issues faster.
|
||||
|
||||
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
|
||||
|
||||
##### Before Submitting A Bug Report
|
||||
|
||||
* Most importantly, check **if you can reproduce the problem** in the [latest version of Umbraco](https://our.umbraco.com/download/). We might have already fixed your particular problem.
|
||||
* Most importantly, check **if you can reproduce the problem** in the [latest version of Umbraco](https://our.umbraco.org/download/). We might have already fixed your particular problem.
|
||||
* It also helps tremendously to check if the issue you're experiencing is present in **a clean install** of the Umbraco version you're currently using. Custom code can have side-effects that don't occur in a clean install.
|
||||
* **Use the Google**. Whatever you're experiencing, Google it plus "Umbraco" - usually you can get some pretty good hints from the search results, including open issues and further troubleshooting hints.
|
||||
* If you do find and existing issue has **and the issue is still open**, add a comment to the existing issue if you have additional information. If you have the same problem and no new info to add, just "star" the issue.
|
||||
@@ -52,7 +52,7 @@ Provide more context by answering these questions:
|
||||
|
||||
Include details about your configuration and environment:
|
||||
|
||||
* **Which version of Umbraco are you using?**
|
||||
* **Which version of Umbraco are you using?**
|
||||
* **What is the environment you're using Umbraco in?** Is this a problem on your local machine or on a server. Tell us about your configuration: Windows version, IIS/IISExpress, database type, etc.
|
||||
* **Which packages do you have installed?**
|
||||
|
||||
@@ -65,11 +65,13 @@ Most of the suggestions in the [reporting bugs](#reporting-bugs) section also co
|
||||
Some additional hints that may be helpful:
|
||||
|
||||
* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of Umbraco which the suggestion is related to.
|
||||
* **Explain why this enhancement would be useful to most Umbraco users** and isn't something that can or should be implemented as a [community package](https://our.umbraco.com/projects/).
|
||||
* **Explain why this enhancement would be useful to most Umbraco users** and isn't something that can or should be implemented as a [community package](https://our.umbraco.org/projects/).
|
||||
|
||||
### Your First Code Contribution
|
||||
|
||||
Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` and issues](https://issues.umbraco.org/issues?q=&project=U4&tagValue=upforgrabs&release=&issueType=&search=search) or on the [new issue tracker](https://github.com/umbraco/Umbraco-CMS/issues?q=is%3Aopen+is%3Aissue+label%3Acommunity%2Fup-for-grabs).
|
||||
Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` and issues](http://issues.umbraco.org/issues/U4?q=%28project%3A+%7BU4%7D+Difficulty%3A+%7BVery+Easy%7D+%23Easy+%23Unresolved+Priority%3A+Normal+%23Major+%23Show-stopper+State%3A+-%7BIn+Progress%7D+sort+by%3A+votes+Affected+versions%3A+-6.*+Affected+versions%3A+-4.*%29+OR+%28tag%3A+%7BUp+For+Grabs%7D+%23Unresolved+%29).
|
||||
|
||||
The issue list is sorted by total number of upvotes. While not perfect, number of upvotes is a reasonable proxy for impact a given change will have.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
@@ -78,9 +80,9 @@ The most successful pull requests usually look a like this:
|
||||
* Fill in the required template
|
||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||
* Unit tests, while optional are awesome, thank you!
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.org/documentation/Reference/) is generated
|
||||
|
||||
Again, these are guidelines, not strict requirements.
|
||||
Again, these are guidelines, not strict requirements.
|
||||
|
||||
## Making changes after the PR was opened
|
||||
|
||||
@@ -90,7 +92,7 @@ If you make the corrections we ask for in the same branch and push them to your
|
||||
|
||||
To be honest, we don't like rules very much. We trust you have the best of intentions and we encourage you to create working code. If it doesn't look perfect then we'll happily help clean it up.
|
||||
|
||||
That said, the Umbraco development team likes to follow the hints that ReSharper gives us (no problem if you don't have this installed) and we've added a `.editorconfig` file so that Visual Studio knows what to do with whitespace, line endings, etc.
|
||||
That said, the Umbraco development team likes to follow the hints that ReSharper gives us (no problem if you don't have this installed) and we've added a `.editorconfig` file so that Visual Studio knows what to do with whitespace, line endings, etc.
|
||||
|
||||
## What should I know before I get started?
|
||||
|
||||
@@ -114,8 +116,8 @@ There's two big areas that you should know about:
|
||||
|
||||
To find the general areas of something you're looking to fix or improve, have a look at the following two parts of the API documentation.
|
||||
|
||||
* [The AngularJS based backoffice files](https://our.umbraco.com/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
|
||||
* [The rest](https://our.umbraco.com/apidocs/csharp/)
|
||||
* [The AngularJS based backoffice files](https://our.umbraco.org/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
|
||||
* [The rest](https://our.umbraco.org/apidocs/csharp/)
|
||||
|
||||
### What branch should I target for my contributions?
|
||||
|
||||
@@ -125,15 +127,9 @@ We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-fl
|
||||
|
||||
### Building Umbraco from source code
|
||||
|
||||
In order to build the Umbraco source code locally, first make sure you have the following installed.
|
||||
|
||||
* Visual Studio 2017 v15.3+
|
||||
* Node v10+ (Installed via `build.bat` script. If you already have it installed, make sure you're running at least v10)
|
||||
* npm v6.4.1+ (Installed via `build.bat` script. If you already have it installed, make sure you're running at least v6.4.1)
|
||||
|
||||
The easiest way to get started is to run `build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
|
||||
|
||||
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 (version 15.3 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
|
||||
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 ([the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
|
||||
|
||||

|
||||
|
||||
@@ -160,4 +156,4 @@ git rebase upstream/dev-v7
|
||||
|
||||
In this command we're syncing with the `dev-v7` branch, but you can of course choose another one if needed.
|
||||
|
||||
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
|
||||
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
|
||||
@@ -13,7 +13,7 @@ We’re usually able to handle small PRs pretty quickly. A community volunteer w
|
||||
|
||||
Umbraco HQ will regularly mark newly created issues on the issue tracker with the `Up for grabs` tag. This means that the proposed changes are wanted in Umbraco but the HQ does not have the time to make them at this time. These issues are usually small enough to fit in the "Small PRs" category and we encourage anyone to pick them up and help out.
|
||||
|
||||
If you do start working on something, make sure to leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
|
||||
If you do start working on something, make sure leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
|
||||
|
||||
## Large PRs
|
||||
New features and large refactorings - can be recognized by seeing a large number of changes, plenty of new files, updates to package manager files (NuGet’s packages.config, NPM’s packages.json, etc.).
|
||||
@@ -30,4 +30,4 @@ If a larger pull request is encouraged by Umbraco HQ, the process will be simila
|
||||
|
||||
If it doesn’t fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and to fix bugs.
|
||||
|
||||
Eventually, a package could "graduate" to be included in the CMS.
|
||||
Eventually, a package could "graduate" to be included in the CMS.
|
||||
@@ -0,0 +1,11 @@
|
||||
### Prerequisites
|
||||
|
||||
- [ ] I have written a descriptive pull-request title
|
||||
- [ ] I have linked this PR to an issue on the tracker at http://issues.umbraco.org
|
||||
|
||||
### Description
|
||||
<!-- A description of the changes proposed in the pull-request -->
|
||||
|
||||
|
||||
|
||||
<!-- Thanks for contributing to Umbraco CMS! -->
|
||||
@@ -0,0 +1,51 @@
|
||||
_You are browsing the Umbraco v8 branch._
|
||||
|
||||
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS) to go to the v7 branch._
|
||||
|
||||
_Ready to try out Version 8? [See the quick start guide](V8_GETTING_STARTED.md)._
|
||||
|
||||
Umbraco CMS
|
||||
===========
|
||||
The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 443,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
|
||||
|
||||
[](https://vimeo.com/172382998/)
|
||||
|
||||
## Umbraco CMS
|
||||
Umbraco is a free open source Content Management System built on the ASP.NET platform. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social.
|
||||
|
||||
## Watch an introduction video
|
||||
|
||||
[](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/)
|
||||
|
||||
## Umbraco - The Friendly CMS
|
||||
|
||||
For the first time on the Microsoft platform, there is a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box.
|
||||
|
||||
Umbraco is not only loved by developers, but is a content editors dream. Enjoy intuitive editing tools, media management, responsive views and approval workflows to send your content live.
|
||||
|
||||
Used by more than 443,000 active websites including Carlsberg, Segway, Amazon and Heinz and **The Official ASP.NET and IIS.NET website from Microsoft** ([https://asp.net](https://asp.net) / [https://iis.net](https://iis.net)), you can be sure that the technology is proven, stable and scales. Backed by the team at Umbraco HQ, and supported by a dedicated community of over 220,000 craftspeople globally, you can trust that Umbraco is a safe choice and is here to stay.
|
||||
|
||||
To view more examples, please visit [https://umbraco.com/case-studies-testimonials/](https://umbraco.com/case-studies-testimonials/)
|
||||
|
||||
## Why Open Source?
|
||||
As an Open Source platform, Umbraco is more than just a CMS. We are transparent with our roadmap for future versions, our incremental sprint planning notes are publicly accessible and community contributions and packages are available for all to use.
|
||||
|
||||
## Trying out Umbraco CMS
|
||||
|
||||
[Umbraco Cloud](https://umbraco.com/cloud) is the easiest and fastest way to use Umbraco yet with full support for all your custom .NET code and intergrations. You're up and running in less than a minute and your life will be made easier with automated upgrades and a built-in deployment engine. We offer a free 14 day trial, no credit card needed.
|
||||
|
||||
If you want to DIY you can [download Umbraco](https://our.umbraco.com/download) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host yourself and handling deployments and upgrades is all down to you.
|
||||
|
||||
## Community
|
||||
|
||||
Our friendly community is available 24/7 at the community hub we call ["Our Umbraco"](https://our.umbraco.com). Our Umbraco feature forums for questions and answers, documentation, downloadable plugins for Umbraco and a rich collection of community resources.
|
||||
|
||||
## Contribute to Umbraco
|
||||
|
||||
Umbraco is contribution focused and community driven. If you want to contribute back to Umbraco please check out our [guide to contributing](CONTRIBUTING.md).
|
||||
|
||||
## Found a bug?
|
||||
|
||||
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](CONTRIBUTING_DETAILED.md#reporting-bugs).
|
||||
|
||||
To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
@@ -23,7 +23,7 @@ We recommend running the site with the Visual Studio since you'll be able to rem
|
||||
|
||||
### Making code changes
|
||||
|
||||
* _[The process for making code changes in v8 is the same as v7](https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md)_
|
||||
* _[The process for making code changes in v8 is the same as v7](https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/docs/CONTRIBUTING.md)_
|
||||
* Any .NET changes you make you just need to compile
|
||||
* Any Angular/JS changes you make you will need to make sure you are running the Gulp build. Easiest way to do this is from within Visual Studio in the `Task Runner Explorer`. You can find this window by pressing `ctrl + q` and typing in `Task Runner Explorer`. In this window you'll see all Gulp tasks, double click on the `dev` task, this will compile the angular solution and start a file watcher, then any html/js changes you make are automatically built.
|
||||
* When making js changes, you should have the chrome developer tools open to ensure that cache is disabled
|
||||
@@ -33,5 +33,5 @@ We recommend running the site with the Visual Studio since you'll be able to rem
|
||||
|
||||
We are keeping track of [known issues and limitations here](http://issues.umbraco.org/issue/U4-11279). These line items will eventually be turned into actual tasks to be worked on. Feel free to help us keep this list updated if you find issues and even help fix some of these items. If there is a particular item you'd like to help fix please mention this on the task and we'll create a sub task for the item to continue discussion there.
|
||||
|
||||
There's [a list of tasks for v8 that haven't been completed](https://github.com/umbraco/Umbraco-CMS/labels/release%2F8.0.0). If you are interested in helping out with any of these please mention this on the task. This list will be constantly updated as we begin to document and design some of the other tasks that still need to get done.
|
||||
There's [a list of tasks for v8 that haven't been completed](http://issues.umbraco.org/issues/U4?q=Due+in+version%3A+8.0.0+%23Unresolved+). If you are interested in helping out with any of these please mention this on the task. This list will be constantly updated as we begin to document and design some of the other tasks that still need to get done.
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
@@ -7,7 +7,7 @@
|
||||
<span class="pull-right">
|
||||
<a href="#top">Back to top</a>
|
||||
</span>
|
||||
<span>Copyright © 2016-present Umbraco<br>Generated by <strong>DocFX</strong></span>
|
||||
<span>Copyright © 2016 Umbraco<br>Generated by <strong>DocFX</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
|
||||
<meta name="generator" content="docfx {{_docfxVersion}}">
|
||||
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
|
||||
<link rel="icon" type="image/png" href="https://our.umbraco.com/assets/images/app-icons/favicon.png">
|
||||
<link rel="icon" type="image/png" href="https://our.umbraco.org/assets/images/app-icons/favicon.png">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.css">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/docfx.css">
|
||||
<link rel="stylesheet" href="{{_rel}}styles/main.css">
|
||||
|
||||
@@ -63,7 +63,7 @@ a:focus {
|
||||
}
|
||||
|
||||
.navbar-header .navbar-brand {
|
||||
background: url(https://our.umbraco.com/assets/images/logo.svg) left center no-repeat;
|
||||
background: url(https://our.umbraco.org/assets/images/logo.svg) left center no-repeat;
|
||||
background-size: 40px auto;
|
||||
width:50px;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Resources;
|
||||
|
||||
[assembly: AssemblyCompany("Umbraco")]
|
||||
[assembly: AssemblyCopyright("Copyright © Umbraco 2018")]
|
||||
[assembly: AssemblyCopyright("Copyright © Umbraco 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -19,4 +19,4 @@ using System.Resources;
|
||||
|
||||
// these are FYI and changed automatically
|
||||
[assembly: AssemblyFileVersion("8.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.0.0-alpha.58")]
|
||||
[assembly: AssemblyInformationalVersion("8.0.0-alpha.44")]
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -10,38 +11,13 @@ using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
public sealed class AuditEventsComponent : IComponent
|
||||
public sealed class AuditEventsComponent : UmbracoComponentBase, IUmbracoCoreComponent
|
||||
{
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IEntityService _entityService;
|
||||
|
||||
public AuditEventsComponent(IAuditService auditService, IUserService userService, IEntityService entityService)
|
||||
{
|
||||
_auditService = auditService;
|
||||
_userService = userService;
|
||||
_entityService = entityService;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
UserService.SavedUserGroup += OnSavedUserGroupWithUsers;
|
||||
|
||||
UserService.SavedUser += OnSavedUser;
|
||||
UserService.DeletedUser += OnDeletedUser;
|
||||
UserService.UserGroupPermissionsAssigned += UserGroupPermissionAssigned;
|
||||
|
||||
MemberService.Saved += OnSavedMember;
|
||||
MemberService.Deleted += OnDeletedMember;
|
||||
MemberService.AssignedRoles += OnAssignedRoles;
|
||||
MemberService.RemovedRoles += OnRemovedRoles;
|
||||
MemberService.Exported += OnMemberExported;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
private IAuditService _auditService;
|
||||
private IUserService _userService;
|
||||
private IEntityService _entityService;
|
||||
|
||||
private IUser CurrentPerformingUser
|
||||
{
|
||||
@@ -71,6 +47,37 @@ namespace Umbraco.Core.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize(IAuditService auditService, IUserService userService, IEntityService entityService)
|
||||
{
|
||||
_auditService = auditService;
|
||||
_userService = userService;
|
||||
_entityService = entityService;
|
||||
|
||||
//BackOfficeUserManager.AccountLocked += ;
|
||||
//BackOfficeUserManager.AccountUnlocked += ;
|
||||
BackOfficeUserManager.ForgotPasswordRequested += OnForgotPasswordRequest;
|
||||
BackOfficeUserManager.ForgotPasswordChangedSuccess += OnForgotPasswordChange;
|
||||
BackOfficeUserManager.LoginFailed += OnLoginFailed;
|
||||
//BackOfficeUserManager.LoginRequiresVerification += ;
|
||||
BackOfficeUserManager.LoginSuccess += OnLoginSuccess;
|
||||
BackOfficeUserManager.LogoutSuccess += OnLogoutSuccess;
|
||||
BackOfficeUserManager.PasswordChanged += OnPasswordChanged;
|
||||
BackOfficeUserManager.PasswordReset += OnPasswordReset;
|
||||
//BackOfficeUserManager.ResetAccessFailedCount += ;
|
||||
|
||||
UserService.SavedUserGroup += OnSavedUserGroupWithUsers;
|
||||
|
||||
UserService.SavedUser += OnSavedUser;
|
||||
UserService.DeletedUser += OnDeletedUser;
|
||||
UserService.UserGroupPermissionsAssigned += UserGroupPermissionAssigned;
|
||||
|
||||
MemberService.Saved += OnSavedMember;
|
||||
MemberService.Deleted += OnDeletedMember;
|
||||
MemberService.AssignedRoles += OnAssignedRoles;
|
||||
MemberService.RemovedRoles += OnRemovedRoles;
|
||||
MemberService.Exported += OnMemberExported;
|
||||
}
|
||||
|
||||
private string FormatEmail(IMember member)
|
||||
{
|
||||
return member == null ? string.Empty : member.Email.IsNullOrWhiteSpace() ? "" : $"<{member.Email}>";
|
||||
@@ -248,6 +255,64 @@ namespace Umbraco.Core.Components
|
||||
"umbraco/user/delete", "delete user");
|
||||
}
|
||||
|
||||
private void OnLoginSuccess(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs)
|
||||
{
|
||||
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
|
||||
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/login", "login success");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLogoutSuccess(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs)
|
||||
{
|
||||
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
|
||||
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/logout", "logout success");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPasswordReset(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
|
||||
{
|
||||
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/reset", "password reset");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPasswordChanged(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
|
||||
{
|
||||
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/change", "password change");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoginFailed(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
|
||||
{
|
||||
WriteAudit(identityArgs.PerformingUser, 0, identityArgs.IpAddress, "umbraco/user/sign-in/failed", "login failed", affectedDetails: "");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnForgotPasswordChange(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
|
||||
{
|
||||
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/change", "password forgot/change");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnForgotPasswordRequest(object sender, EventArgs args)
|
||||
{
|
||||
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
|
||||
{
|
||||
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/request", "password forgot/request");
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteAudit(int performingId, int affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null)
|
||||
{
|
||||
var performingUser = _userService.GetUserById(performingId);
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Web.Security
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is used by events raised from hthe BackofficeUserManager
|
||||
@@ -18,7 +18,10 @@ namespace Umbraco.Core
|
||||
// this only gets called when an assembly can't be resolved
|
||||
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
||||
}
|
||||
|
||||
|
||||
private static readonly Regex Log4NetAssemblyPattern = new Regex("log4net, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=\\w+$", RegexOptions.Compiled);
|
||||
private const string Log4NetReplacement = "log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a";
|
||||
|
||||
/// <summary>
|
||||
/// This is used to do an assembly binding redirect via code - normally required due to signature changes in assemblies
|
||||
/// </summary>
|
||||
@@ -27,6 +30,12 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
//log4net:
|
||||
if (Log4NetAssemblyPattern.IsMatch(args.Name) && args.Name != Log4NetReplacement)
|
||||
{
|
||||
return Assembly.Load(Log4NetAssemblyPattern.Replace(args.Name, Log4NetReplacement));
|
||||
}
|
||||
|
||||
//AutoMapper:
|
||||
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
|
||||
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static class ByteArrayExtensions
|
||||
{
|
||||
private static readonly char[] BytesToHexStringLookup = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
public static string ToHexString(this byte[] bytes)
|
||||
{
|
||||
int i = 0, p = 0, bytesLength = bytes.Length;
|
||||
var chars = new char[bytesLength * 2];
|
||||
while (i < bytesLength)
|
||||
{
|
||||
var b = bytes[i++];
|
||||
chars[p++] = BytesToHexStringLookup[b / 0x10];
|
||||
chars[p++] = BytesToHexStringLookup[b % 0x10];
|
||||
}
|
||||
return new string(chars, 0, chars.Length);
|
||||
}
|
||||
|
||||
public static string ToHexString(this byte[] bytes, char separator, int blockSize, int blockCount)
|
||||
{
|
||||
int p = 0, bytesLength = bytes.Length, count = 0, size = 0;
|
||||
var chars = new char[bytesLength * 2 + blockCount];
|
||||
for (var i = 0; i < bytesLength; i++)
|
||||
{
|
||||
var b = bytes[i++];
|
||||
chars[p++] = BytesToHexStringLookup[b / 0x10];
|
||||
chars[p++] = BytesToHexStringLookup[b % 0x10];
|
||||
if (count == blockCount) continue;
|
||||
if (++size < blockSize) continue;
|
||||
|
||||
chars[p++] = '/';
|
||||
size = 0;
|
||||
count++;
|
||||
}
|
||||
return new string(chars, 0, chars.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,27 @@ using System.Web;
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the application-wide caches.
|
||||
/// Class that is exposed by the ApplicationContext for application wide caching purposes
|
||||
/// </summary>
|
||||
public class CacheHelper
|
||||
{
|
||||
public static CacheHelper NoCache { get; } = new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cache helper with disabled caches
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Good for unit testing
|
||||
/// </remarks>
|
||||
public static CacheHelper CreateDisabledCacheHelper()
|
||||
{
|
||||
// do *not* return NoCache
|
||||
// NoCache is a special instance that is detected by RepositoryBase and disables all cache policies
|
||||
// CreateDisabledCacheHelper is used in tests to use no cache, *but* keep all cache policies
|
||||
return new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance for use in the web
|
||||
/// </summary>
|
||||
@@ -23,6 +40,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <summary>
|
||||
/// Initializes a new instance for use in the web
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public CacheHelper(System.Web.Caching.Cache cache)
|
||||
: this(
|
||||
new HttpRuntimeCacheProvider(cache),
|
||||
@@ -32,39 +50,30 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance based on the provided providers
|
||||
/// </summary>
|
||||
/// <param name="httpCacheProvider"></param>
|
||||
/// <param name="staticCacheProvider"></param>
|
||||
/// <param name="requestCacheProvider"></param>
|
||||
/// <param name="isolatedCacheManager"></param>
|
||||
public CacheHelper(
|
||||
IRuntimeCacheProvider httpCacheProvider,
|
||||
ICacheProvider staticCacheProvider,
|
||||
ICacheProvider requestCacheProvider,
|
||||
IsolatedRuntimeCache isolatedCacheManager)
|
||||
{
|
||||
RuntimeCache = httpCacheProvider ?? throw new ArgumentNullException(nameof(httpCacheProvider));
|
||||
StaticCache = staticCacheProvider ?? throw new ArgumentNullException(nameof(staticCacheProvider));
|
||||
RequestCache = requestCacheProvider ?? throw new ArgumentNullException(nameof(requestCacheProvider));
|
||||
IsolatedRuntimeCache = isolatedCacheManager ?? throw new ArgumentNullException(nameof(isolatedCacheManager));
|
||||
if (httpCacheProvider == null) throw new ArgumentNullException("httpCacheProvider");
|
||||
if (staticCacheProvider == null) throw new ArgumentNullException("staticCacheProvider");
|
||||
if (requestCacheProvider == null) throw new ArgumentNullException("requestCacheProvider");
|
||||
if (isolatedCacheManager == null) throw new ArgumentNullException("isolatedCacheManager");
|
||||
RuntimeCache = httpCacheProvider;
|
||||
StaticCache = staticCacheProvider;
|
||||
RequestCache = requestCacheProvider;
|
||||
IsolatedRuntimeCache = isolatedCacheManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the special disabled instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When used by repositories, all cache policies apply, but the underlying caches do not cache anything.</para>
|
||||
/// <para>Used by tests.</para>
|
||||
/// </remarks>
|
||||
public static CacheHelper Disabled { get; } = new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the special no-cache instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When used by repositories, all cache policies are bypassed.</para>
|
||||
/// <para>Used by repositories that do no cache.</para>
|
||||
/// </remarks>
|
||||
public static CacheHelper NoCache { get; } = new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Request cache
|
||||
/// </summary>
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
using Umbraco.Core.Composing;
|
||||
using System.Collections.Generic;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
public class CacheRefresherCollectionBuilder : LazyCollectionBuilderBase<CacheRefresherCollectionBuilder, CacheRefresherCollection, ICacheRefresher>
|
||||
{
|
||||
public CacheRefresherCollectionBuilder(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected override CacheRefresherCollectionBuilder This => this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Core.CodeAnnotations
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal class ActionMetadataAttribute : Attribute
|
||||
{
|
||||
public string Category { get; }
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor used to assign a Category, since no name is assigned it will try to be translated from the language files based on the action's alias
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
public ActionMetadataAttribute(string category)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(category)) throw new ArgumentNullOrEmptyException(nameof(category));
|
||||
Category = category;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor used to assign an explicit name and category
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
/// <param name="name"></param>
|
||||
public ActionMetadataAttribute(string category, string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(category)) throw new ArgumentNullOrEmptyException(nameof(category));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
Category = category;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,4 +40,4 @@ namespace Umbraco.Core.Collections
|
||||
public static bool operator !=(CompositeIntStringKey key1, CompositeIntStringKey key2)
|
||||
=> key1._key2 != key2._key2 || key1._key1 != key2._key1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,10 @@ namespace Umbraco.Core.Collections
|
||||
/// The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public int Count => GetThreadSafeClone().Count;
|
||||
public int Count
|
||||
{
|
||||
get { return GetThreadSafeClone().Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
|
||||
@@ -78,7 +81,10 @@ namespace Umbraco.Core.Collections
|
||||
/// <returns>
|
||||
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
|
||||
/// </returns>
|
||||
public bool IsReadOnly => false;
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
|
||||
@@ -14,31 +14,30 @@ namespace Umbraco.Core.Collections
|
||||
/// </remarks>
|
||||
/// <typeparam name="TValue">The type of elements contained in the BindableCollection</typeparam>
|
||||
/// <typeparam name="TKey">The type of the indexing key</typeparam>
|
||||
public class ObservableDictionary<TKey, TValue> : ObservableCollection<TValue>, IReadOnlyDictionary<TKey, TValue>, IDictionary<TKey, TValue>
|
||||
public class ObservableDictionary<TKey, TValue> : ObservableCollection<TValue>
|
||||
{
|
||||
protected Dictionary<TKey, int> Indecies { get; }
|
||||
protected Func<TValue, TKey> KeySelector { get; }
|
||||
protected Dictionary<TKey, int> Indecies = new Dictionary<TKey, int>();
|
||||
protected Func<TValue, TKey> KeySelector;
|
||||
|
||||
/// <summary>
|
||||
/// Create new ObservableDictionary
|
||||
/// </summary>
|
||||
/// <param name="keySelector">Selector function to create key from value</param>
|
||||
/// <param name="equalityComparer">The equality comparer to use when comparing keys, or null to use the default comparer.</param>
|
||||
public ObservableDictionary(Func<TValue, TKey> keySelector, IEqualityComparer<TKey> equalityComparer = null)
|
||||
public ObservableDictionary(Func<TValue, TKey> keySelector)
|
||||
: base()
|
||||
{
|
||||
KeySelector = keySelector ?? throw new ArgumentException("keySelector");
|
||||
Indecies = new Dictionary<TKey, int>(equalityComparer);
|
||||
if (keySelector == null) throw new ArgumentException("keySelector");
|
||||
KeySelector = keySelector;
|
||||
}
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override void InsertItem(int index, TValue item)
|
||||
{
|
||||
var key = KeySelector(item);
|
||||
if (Indecies.ContainsKey(key))
|
||||
throw new DuplicateKeyException(key.ToString());
|
||||
|
||||
if (index != Count)
|
||||
if (index != this.Count)
|
||||
{
|
||||
foreach (var k in Indecies.Keys.Where(k => Indecies[k] >= index).ToList())
|
||||
{
|
||||
@@ -48,6 +47,7 @@ namespace Umbraco.Core.Collections
|
||||
|
||||
base.InsertItem(index, item);
|
||||
Indecies[key] = index;
|
||||
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
@@ -56,6 +56,7 @@ namespace Umbraco.Core.Collections
|
||||
Indecies.Clear();
|
||||
}
|
||||
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
var item = this[index];
|
||||
@@ -70,10 +71,9 @@ namespace Umbraco.Core.Collections
|
||||
Indecies[k]--;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
public virtual bool ContainsKey(TKey key)
|
||||
{
|
||||
return Indecies.ContainsKey(key);
|
||||
}
|
||||
@@ -83,10 +83,10 @@ namespace Umbraco.Core.Collections
|
||||
/// </summary>
|
||||
/// <param name="key">Key of element to replace</param>
|
||||
/// <returns></returns>
|
||||
public TValue this[TKey key]
|
||||
public virtual TValue this[TKey key]
|
||||
{
|
||||
|
||||
get => this[Indecies[key]];
|
||||
get { return this[Indecies[key]]; }
|
||||
set
|
||||
{
|
||||
//confirm key matches
|
||||
@@ -95,7 +95,7 @@ namespace Umbraco.Core.Collections
|
||||
|
||||
if (!Indecies.ContainsKey(key))
|
||||
{
|
||||
Add(value);
|
||||
this.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -112,10 +112,9 @@ namespace Umbraco.Core.Collections
|
||||
///
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <returns>False if key not found</returns>
|
||||
public bool Replace(TKey key, TValue value)
|
||||
public virtual bool Replace(TKey key, TValue value)
|
||||
{
|
||||
if (!Indecies.ContainsKey(key)) return false;
|
||||
|
||||
//confirm key matches
|
||||
if (!KeySelector(value).Equals(key))
|
||||
throw new InvalidOperationException("Key of new value does not match");
|
||||
@@ -125,11 +124,11 @@ namespace Umbraco.Core.Collections
|
||||
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
public virtual bool Remove(TKey key)
|
||||
{
|
||||
if (!Indecies.ContainsKey(key)) return false;
|
||||
|
||||
RemoveAt(Indecies[key]);
|
||||
this.RemoveAt(Indecies[key]);
|
||||
return true;
|
||||
|
||||
}
|
||||
@@ -139,13 +138,12 @@ namespace Umbraco.Core.Collections
|
||||
/// </summary>
|
||||
/// <param name="currentKey"></param>
|
||||
/// <param name="newKey"></param>
|
||||
public void ChangeKey(TKey currentKey, TKey newKey)
|
||||
public virtual void ChangeKey(TKey currentKey, TKey newKey)
|
||||
{
|
||||
if (!Indecies.ContainsKey(currentKey))
|
||||
{
|
||||
throw new InvalidOperationException("No item with the key " + currentKey + "was found in the collection");
|
||||
}
|
||||
|
||||
if (ContainsKey(newKey))
|
||||
{
|
||||
throw new DuplicateKeyException(newKey.ToString());
|
||||
@@ -157,81 +155,16 @@ namespace Umbraco.Core.Collections
|
||||
Indecies.Add(newKey, currentIndex);
|
||||
}
|
||||
|
||||
#region IDictionary and IReadOnlyDictionary implementation
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue val)
|
||||
{
|
||||
if (Indecies.TryGetValue(key, out var index))
|
||||
{
|
||||
val = this[index];
|
||||
return true;
|
||||
}
|
||||
val = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all keys
|
||||
/// </summary>
|
||||
public IEnumerable<TKey> Keys => Indecies.Keys;
|
||||
|
||||
/// <summary>
|
||||
/// Returns all values
|
||||
/// </summary>
|
||||
public IEnumerable<TValue> Values => base.Items;
|
||||
|
||||
ICollection<TKey> IDictionary<TKey, TValue>.Keys => Indecies.Keys;
|
||||
|
||||
//this will never be used
|
||||
ICollection<TValue> IDictionary<TKey, TValue>.Values => Values.ToList();
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
|
||||
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
||||
{
|
||||
foreach (var i in Values)
|
||||
{
|
||||
var key = KeySelector(i);
|
||||
yield return new KeyValuePair<TKey, TValue>(key, i);
|
||||
}
|
||||
}
|
||||
|
||||
void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
|
||||
{
|
||||
Add(value);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
Add(item.Value);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return ContainsKey(item.Key);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return Remove(item.Key);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal class DuplicateKeyException : Exception
|
||||
{
|
||||
|
||||
public string Key { get; private set; }
|
||||
public DuplicateKeyException(string key)
|
||||
: base("Attempted to insert duplicate key \"" + key + "\" in collection.")
|
||||
: base("Attempted to insert duplicate key " + key + " in collection")
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
public sealed class AuditEventsComposer : ComponentComposer<AuditEventsComponent>, ICoreComposer
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
// note: this class is NOT thread-safe in any ways
|
||||
|
||||
internal class BootLoader
|
||||
{
|
||||
private readonly IServiceContainer _container;
|
||||
private readonly ProfilingLogger _proflog;
|
||||
private readonly ILogger _logger;
|
||||
private IUmbracoComponent[] _components;
|
||||
private bool _booted;
|
||||
|
||||
private const int LogThresholdMilliseconds = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BootLoader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="container">The application container.</param>
|
||||
public BootLoader(IServiceContainer container)
|
||||
{
|
||||
_container = container ?? throw new ArgumentNullException(nameof(container));
|
||||
_proflog = container.GetInstance<ProfilingLogger>();
|
||||
_logger = container.GetInstance<ILogger>();
|
||||
}
|
||||
|
||||
private class EnableInfo
|
||||
{
|
||||
public bool Enabled;
|
||||
public int Weight = -1;
|
||||
}
|
||||
|
||||
public void Boot(IEnumerable<Type> componentTypes, RuntimeLevel level)
|
||||
{
|
||||
if (_booted) throw new InvalidOperationException("Can not boot, has already booted.");
|
||||
|
||||
var orderedComponentTypes = PrepareComponentTypes(componentTypes, level);
|
||||
|
||||
InstanciateComponents(orderedComponentTypes);
|
||||
ComposeComponents(level);
|
||||
|
||||
using (var scope = _container.GetInstance<IScopeProvider>().CreateScope())
|
||||
{
|
||||
InitializeComponents();
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
// rejoice!
|
||||
_booted = true;
|
||||
}
|
||||
|
||||
private IEnumerable<Type> PrepareComponentTypes(IEnumerable<Type> componentTypes, RuntimeLevel level)
|
||||
{
|
||||
using (_proflog.DebugDuration<BootLoader>("Preparing component types.", "Prepared component types."))
|
||||
{
|
||||
return PrepareComponentTypes2(componentTypes, level);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Type> PrepareComponentTypes2(IEnumerable<Type> componentTypes, RuntimeLevel level)
|
||||
{
|
||||
// create a list, remove those that cannot be enabled due to runtime level
|
||||
var componentTypeList = componentTypes
|
||||
.Where(x =>
|
||||
{
|
||||
// use the min level specified by the attribute if any
|
||||
// otherwise, user components have Run min level, anything else is Unknown (always run)
|
||||
var attr = x.GetCustomAttribute<RuntimeLevelAttribute>();
|
||||
var minLevel = attr?.MinLevel ?? (x.Implements<IUmbracoUserComponent>() ? RuntimeLevel.Run : RuntimeLevel.Unknown);
|
||||
return level >= minLevel;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// cannot remove that one - ever
|
||||
if (componentTypeList.Contains(typeof(UmbracoCoreComponent)) == false)
|
||||
componentTypeList.Add(typeof(UmbracoCoreComponent));
|
||||
|
||||
// enable or disable components
|
||||
EnableDisableComponents(componentTypeList);
|
||||
|
||||
// sort the components according to their dependencies
|
||||
var requirements = new Dictionary<Type, List<Type>>();
|
||||
foreach (var type in componentTypeList) requirements[type] = null;
|
||||
foreach (var type in componentTypeList)
|
||||
{
|
||||
GatherRequirementsFromRequireAttribute(type, componentTypeList, requirements);
|
||||
GatherRequirementsFromRequiredAttribute(type, componentTypeList, requirements);
|
||||
}
|
||||
|
||||
// only for debugging, this is verbose
|
||||
//_logger.Debug<BootLoader>(GetComponentsReport(requirements));
|
||||
|
||||
// sort components
|
||||
var graph = new TopoGraph<Type, KeyValuePair<Type, List<Type>>>(kvp => kvp.Key, kvp => kvp.Value);
|
||||
graph.AddItems(requirements);
|
||||
List<Type> sortedComponentTypes;
|
||||
try
|
||||
{
|
||||
sortedComponentTypes = graph.GetSortedItems().Select(x => x.Key).ToList();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// in case of an error, force-dump everything to log
|
||||
_logger.Info<BootLoader>(() => GetComponentsReport(requirements));
|
||||
_logger.Error<BootLoader>("Failed to sort components.", e);
|
||||
throw;
|
||||
}
|
||||
|
||||
// bit verbose but should help for troubleshooting
|
||||
var text = "Ordered Components: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComponentTypes) + Environment.NewLine;
|
||||
Console.WriteLine(text);
|
||||
_logger.Debug<BootLoader>(text);
|
||||
|
||||
return sortedComponentTypes;
|
||||
}
|
||||
|
||||
private static string GetComponentsReport(Dictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
text.AppendLine("Components & Dependencies:");
|
||||
text.AppendLine();
|
||||
|
||||
foreach (var kvp in requirements)
|
||||
{
|
||||
var type = kvp.Key;
|
||||
|
||||
text.AppendLine(type.FullName);
|
||||
foreach (var attribute in type.GetCustomAttributes<RequireComponentAttribute>())
|
||||
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
|
||||
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
|
||||
: ""));
|
||||
foreach (var attribute in type.GetCustomAttributes<RequiredComponentAttribute>())
|
||||
text.AppendLine(" -< " + attribute.RequiringType);
|
||||
foreach (var i in type.GetInterfaces())
|
||||
{
|
||||
text.AppendLine(" : " + i.FullName);
|
||||
foreach (var attribute in i.GetCustomAttributes<RequireComponentAttribute>())
|
||||
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
|
||||
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
|
||||
: ""));
|
||||
foreach (var attribute in i.GetCustomAttributes<RequiredComponentAttribute>())
|
||||
text.AppendLine(" -< " + attribute.RequiringType);
|
||||
}
|
||||
if (kvp.Value != null)
|
||||
foreach (var t in kvp.Value)
|
||||
text.AppendLine(" = " + t);
|
||||
text.AppendLine();
|
||||
}
|
||||
text.AppendLine("/");
|
||||
text.AppendLine();
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
private static void EnableDisableComponents(ICollection<Type> types)
|
||||
{
|
||||
var enabled = new Dictionary<Type, EnableInfo>();
|
||||
|
||||
// process the enable/disable attributes
|
||||
// these two attributes are *not* inherited and apply to *classes* only (not interfaces).
|
||||
// remote declarations (when a component enables/disables *another* component)
|
||||
// have priority over local declarations (when a component disables itself) so that
|
||||
// ppl can enable components that, by default, are disabled.
|
||||
// what happens in case of conflicting remote declarations is unspecified. more
|
||||
// precisely, the last declaration to be processed wins, but the order of the
|
||||
// declarations depends on the type finder and is unspecified.
|
||||
foreach (var componentType in types)
|
||||
{
|
||||
foreach (var attr in componentType.GetCustomAttributes<EnableComponentAttribute>())
|
||||
{
|
||||
var type = attr.EnabledType ?? componentType;
|
||||
if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo();
|
||||
var weight = type == componentType ? 1 : 2;
|
||||
if (enableInfo.Weight > weight) continue;
|
||||
|
||||
enableInfo.Enabled = true;
|
||||
enableInfo.Weight = weight;
|
||||
}
|
||||
foreach (var attr in componentType.GetCustomAttributes<DisableComponentAttribute>())
|
||||
{
|
||||
var type = attr.DisabledType ?? componentType;
|
||||
if (type == typeof(UmbracoCoreComponent)) throw new InvalidOperationException("Cannot disable UmbracoCoreComponent.");
|
||||
if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo();
|
||||
var weight = type == componentType ? 1 : 2;
|
||||
if (enableInfo.Weight > weight) continue;
|
||||
|
||||
enableInfo.Enabled = false;
|
||||
enableInfo.Weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
// remove components that end up being disabled
|
||||
foreach (var kvp in enabled.Where(x => x.Value.Enabled == false))
|
||||
types.Remove(kvp.Key);
|
||||
}
|
||||
|
||||
private static void GatherRequirementsFromRequireAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
// get 'require' attributes
|
||||
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
|
||||
var requireAttributes = type
|
||||
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<RequireComponentAttribute>()) // those marking interfaces
|
||||
.Concat(type.GetCustomAttributes<RequireComponentAttribute>()); // those marking the component
|
||||
|
||||
// what happens in case of conflicting attributes (different strong/weak for same type) is not specified.
|
||||
foreach (var attr in requireAttributes)
|
||||
{
|
||||
if (attr.RequiredType == type) continue; // ignore self-requirements (+ exclude in implems, below)
|
||||
|
||||
// requiring an interface = require any enabled component implementing that interface
|
||||
// unless strong, and then require at least one enabled component implementing that interface
|
||||
if (attr.RequiredType.IsInterface)
|
||||
{
|
||||
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x)).ToList();
|
||||
if (implems.Count > 0)
|
||||
{
|
||||
if (requirements[type] == null) requirements[type] = new List<Type>();
|
||||
requirements[type].AddRange(implems);
|
||||
}
|
||||
else if (attr.Weak == false) // if explicitely set to !weak, is strong, else is weak
|
||||
throw new Exception($"Broken component dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
|
||||
}
|
||||
// requiring a class = require that the component is enabled
|
||||
// unless weak, and then requires it if it is enabled
|
||||
else
|
||||
{
|
||||
if (types.Contains(attr.RequiredType))
|
||||
{
|
||||
if (requirements[type] == null) requirements[type] = new List<Type>();
|
||||
requirements[type].Add(attr.RequiredType);
|
||||
}
|
||||
else if (attr.Weak != true) // if not explicitely set to weak, is strong
|
||||
throw new Exception($"Broken component dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void GatherRequirementsFromRequiredAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
// get 'required' attributes
|
||||
// fixme explain
|
||||
var requiredAttributes = type
|
||||
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<RequiredComponentAttribute>())
|
||||
.Concat(type.GetCustomAttributes<RequiredComponentAttribute>());
|
||||
|
||||
foreach (var attr in requiredAttributes)
|
||||
{
|
||||
if (attr.RequiringType == type) continue; // ignore self-requirements (+ exclude in implems, below)
|
||||
|
||||
if (attr.RequiringType.IsInterface)
|
||||
{
|
||||
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x)).ToList();
|
||||
foreach (var implem in implems)
|
||||
{
|
||||
if (requirements[implem] == null) requirements[implem] = new List<Type>();
|
||||
requirements[implem].Add(type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (types.Contains(attr.RequiringType))
|
||||
{
|
||||
if (requirements[attr.RequiringType] == null) requirements[attr.RequiringType] = new List<Type>();
|
||||
requirements[attr.RequiringType].Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InstanciateComponents(IEnumerable<Type> types)
|
||||
{
|
||||
using (_proflog.DebugDuration<BootLoader>("Instanciating components.", "Instanciated components."))
|
||||
{
|
||||
_components = types.Select(x => (IUmbracoComponent) Activator.CreateInstance(x)).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private void ComposeComponents(RuntimeLevel level)
|
||||
{
|
||||
using (_proflog.DebugDuration<BootLoader>($"Composing components. (log when >{LogThresholdMilliseconds}ms)", "Composed components."))
|
||||
{
|
||||
var composition = new Composition(_container, level);
|
||||
foreach (var component in _components)
|
||||
{
|
||||
var componentType = component.GetType();
|
||||
using (_proflog.DebugDuration<BootLoader>($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
component.Compose(composition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeComponents()
|
||||
{
|
||||
// use a container scope to ensure that PerScope instances are disposed
|
||||
// components that require instances that should not survive should register them with PerScope lifetime
|
||||
using (_proflog.DebugDuration<BootLoader>($"Initializing components. (log when >{LogThresholdMilliseconds}ms)", "Initialized components."))
|
||||
using (_container.BeginScope())
|
||||
{
|
||||
foreach (var component in _components)
|
||||
{
|
||||
var componentType = component.GetType();
|
||||
var initializers = componentType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(x => x.Name == "Initialize" && x.IsGenericMethod == false);
|
||||
using (_proflog.DebugDuration<BootLoader>($"Initializing {componentType.FullName}.", $"Initialised {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
foreach (var initializer in initializers)
|
||||
{
|
||||
var parameters = initializer.GetParameters()
|
||||
.Select(x => GetParameter(componentType, x.ParameterType))
|
||||
.ToArray();
|
||||
initializer.Invoke(component, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object GetParameter(Type componentType, Type parameterType)
|
||||
{
|
||||
object param;
|
||||
|
||||
try
|
||||
{
|
||||
param = _container.TryGetInstance(parameterType);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new BootFailedException($"Could not get parameter of type {parameterType.FullName} for component {componentType.FullName}.", e);
|
||||
}
|
||||
|
||||
if (param == null) throw new BootFailedException($"Could not get parameter of type {parameterType.FullName} for component {componentType.FullName}.");
|
||||
return param;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
if (_booted == false)
|
||||
{
|
||||
_proflog.Logger.Warn<BootLoader>("Cannot terminate, has not booted.");
|
||||
return;
|
||||
}
|
||||
|
||||
using (_proflog.DebugDuration<BootLoader>($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated."))
|
||||
{
|
||||
for (var i = _components.Length - 1; i >= 0; i--) // terminate components in reverse order
|
||||
{
|
||||
var component = _components[i];
|
||||
var componentType = component.GetType();
|
||||
using (_proflog.DebugDuration<BootLoader>($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
component.Terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the collection of <see cref="IComponent"/> implementations.
|
||||
/// </summary>
|
||||
public class ComponentCollection : BuilderCollectionBase<IComponent>
|
||||
{
|
||||
private const int LogThresholdMilliseconds = 100;
|
||||
|
||||
private readonly IProfilingLogger _logger;
|
||||
|
||||
public ComponentCollection(IEnumerable<IComponent> items, IProfilingLogger logger)
|
||||
: base(items)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized."))
|
||||
{
|
||||
foreach (var component in this.Reverse()) // terminate components in reverse order
|
||||
{
|
||||
var componentType = component.GetType();
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
component.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated."))
|
||||
{
|
||||
foreach (var component in this.Reverse()) // terminate components in reverse order
|
||||
{
|
||||
var componentType = component.GetType();
|
||||
using (_logger.DebugDuration<ComponentCollection>($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
component.Terminate();
|
||||
component.DisposeIfDisposable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds a <see cref="ComponentCollection"/>.
|
||||
/// </summary>
|
||||
public class ComponentCollectionBuilder : OrderedCollectionBuilderBase<ComponentCollectionBuilder, ComponentCollection, IComponent>
|
||||
{
|
||||
private const int LogThresholdMilliseconds = 100;
|
||||
|
||||
private IProfilingLogger _logger;
|
||||
|
||||
public ComponentCollectionBuilder()
|
||||
{ }
|
||||
|
||||
protected override ComponentCollectionBuilder This => this;
|
||||
|
||||
protected override IEnumerable<IComponent> CreateItems(IFactory factory)
|
||||
{
|
||||
_logger = factory.GetInstance<IProfilingLogger>();
|
||||
|
||||
using (_logger.DebugDuration<ComponentCollectionBuilder>($"Creating components. (log when >{LogThresholdMilliseconds}ms)", "Created."))
|
||||
{
|
||||
return base.CreateItems(factory);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IComponent CreateItem(IFactory factory, Type itemType)
|
||||
{
|
||||
using (_logger.DebugDuration<Composers>($"Creating {itemType.FullName}.", $"Created {itemType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
return base.CreateItem(factory, itemType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for composers which compose a component.
|
||||
/// </summary>
|
||||
/// <typeparam name="TComponent">The type of the component</typeparam>
|
||||
public abstract class ComponentComposer<TComponent> : IComposer
|
||||
where TComponent : IComponent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public virtual void Compose(Composition composition)
|
||||
{
|
||||
composition.Components().Append<TComponent>();
|
||||
}
|
||||
|
||||
// note: thanks to this class, a component that does not compose anything can be
|
||||
// registered with one line:
|
||||
// public class MyComponentComposer : ComponentComposer<MyComponent> { }
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer requires another composer.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This attribute is *not* inherited. This means that a composer class inheriting from
|
||||
/// another composer class does *not* inherit its requirements. However, the runtime checks
|
||||
/// the *interfaces* of every composer for their requirements, so requirements declared on
|
||||
/// interfaces are inherited by every composer class implementing the interface.</para>
|
||||
/// <para>When targeting a class, indicates a dependency on the composer which must be enabled,
|
||||
/// unless the requirement has explicitly been declared as weak (and then, only if the composer
|
||||
/// is enabled).</para>
|
||||
/// <para>When targeting an interface, indicates a dependency on enabled composers implementing
|
||||
/// the interface. It could be no composer at all, unless the requirement has explicitly been
|
||||
/// declared as strong (and at least one composer must be enabled).</para>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class ComposeAfterAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ComposeAfterAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredType">The type of the required composer.</param>
|
||||
public ComposeAfterAttribute(Type requiredType)
|
||||
{
|
||||
if (typeof(IComposer).IsAssignableFrom(requiredType) == false)
|
||||
throw new ArgumentException($"Type {requiredType.FullName} is invalid here because it does not implement {typeof(IComposer).FullName}.");
|
||||
RequiredType = requiredType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ComposeAfterAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredType">The type of the required composer.</param>
|
||||
/// <param name="weak">A value indicating whether the requirement is weak.</param>
|
||||
public ComposeAfterAttribute(Type requiredType, bool weak)
|
||||
: this(requiredType)
|
||||
{
|
||||
Weak = weak;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the required type.
|
||||
/// </summary>
|
||||
public Type RequiredType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the requirement is weak.
|
||||
/// </summary>
|
||||
/// <remarks>Returns <c>true</c> if the requirement is weak (requires the other composer if it
|
||||
/// is enabled), <c>false</c> if the requirement is strong (requires the other composer to be
|
||||
/// enabled), and <c>null</c> if unspecified, in which case it is strong for classes and weak for
|
||||
/// interfaces.</remarks>
|
||||
public bool? Weak { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a component is required by another composer.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This attribute is *not* inherited. This means that a composer class inheriting from
|
||||
/// another composer class does *not* inherit its requirements. However, the runtime checks
|
||||
/// the *interfaces* of every composer for their requirements, so requirements declared on
|
||||
/// interfaces are inherited by every composer class implementing the interface.</para>
|
||||
/// <para>When targeting a class, indicates a dependency on the composer which must be enabled,
|
||||
/// unless the requirement has explicitly been declared as weak (and then, only if the composer
|
||||
/// is enabled).</para>
|
||||
/// <para>When targeting an interface, indicates a dependency on enabled composers implementing
|
||||
/// the interface. It could be no composer at all, unless the requirement has explicitly been
|
||||
/// declared as strong (and at least one composer must be enabled).</para>
|
||||
/// </remarks>
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class ComposeBeforeAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ComposeBeforeAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiringType">The type of the required composer.</param>
|
||||
public ComposeBeforeAttribute(Type requiringType)
|
||||
{
|
||||
if (typeof(IComposer).IsAssignableFrom(requiringType) == false)
|
||||
throw new ArgumentException($"Type {requiringType.FullName} is invalid here because it does not implement {typeof(IComposer).FullName}.");
|
||||
RequiringType = requiringType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the required type.
|
||||
/// </summary>
|
||||
public Type RequiringType { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
// note: this class is NOT thread-safe in any ways
|
||||
|
||||
/// <summary>
|
||||
/// Handles the composers.
|
||||
/// </summary>
|
||||
public class Composers
|
||||
{
|
||||
private readonly Composition _composition;
|
||||
private readonly IProfilingLogger _logger;
|
||||
private readonly IEnumerable<Type> _composerTypes;
|
||||
|
||||
private const int LogThresholdMilliseconds = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Composers"/> class.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="composerTypes">The composer types.</param>
|
||||
/// <param name="logger">A profiling logger.</param>
|
||||
public Composers(Composition composition, IEnumerable<Type> composerTypes, IProfilingLogger logger)
|
||||
{
|
||||
_composition = composition ?? throw new ArgumentNullException(nameof(composition));
|
||||
_composerTypes = composerTypes ?? throw new ArgumentNullException(nameof(composerTypes));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
private class EnableInfo
|
||||
{
|
||||
public bool Enabled;
|
||||
public int Weight = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates and composes the composers.
|
||||
/// </summary>
|
||||
public void Compose()
|
||||
{
|
||||
// make sure it is there
|
||||
_composition.WithCollectionBuilder<ComponentCollectionBuilder>();
|
||||
|
||||
IEnumerable<Type> orderedComposerTypes;
|
||||
|
||||
using (_logger.DebugDuration<Composers>("Preparing composer types.", "Prepared composer types."))
|
||||
{
|
||||
orderedComposerTypes = PrepareComposerTypes();
|
||||
}
|
||||
|
||||
var composers = InstantiateComposers(orderedComposerTypes);
|
||||
|
||||
using (_logger.DebugDuration<Composers>($"Composing composers. (log when >{LogThresholdMilliseconds}ms)", "Composed composers."))
|
||||
{
|
||||
foreach (var composer in composers)
|
||||
{
|
||||
var componentType = composer.GetType();
|
||||
using (_logger.DebugDuration<Composers>($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
|
||||
{
|
||||
composer.Compose(_composition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Type> PrepareComposerTypes()
|
||||
{
|
||||
// create a list, remove those that cannot be enabled due to runtime level
|
||||
var composerTypeList = _composerTypes
|
||||
.Where(x =>
|
||||
{
|
||||
// use the min level specified by the attribute if any
|
||||
// otherwise, user composers have Run min level, anything else is Unknown (always run)
|
||||
var attr = x.GetCustomAttribute<RuntimeLevelAttribute>();
|
||||
var minLevel = attr?.MinLevel ?? (x.Implements<IUserComposer>() ? RuntimeLevel.Run : RuntimeLevel.Unknown);
|
||||
return _composition.RuntimeState.Level >= minLevel;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// enable or disable composers
|
||||
EnableDisableComposers(composerTypeList);
|
||||
|
||||
// sort the composers according to their dependencies
|
||||
var requirements = new Dictionary<Type, List<Type>>();
|
||||
foreach (var type in composerTypeList) requirements[type] = null;
|
||||
foreach (var type in composerTypeList)
|
||||
{
|
||||
GatherRequirementsFromRequireAttribute(type, composerTypeList, requirements);
|
||||
GatherRequirementsFromRequiredByAttribute(type, composerTypeList, requirements);
|
||||
}
|
||||
|
||||
// only for debugging, this is verbose
|
||||
//_logger.Debug<Composers>(GetComposersReport(requirements));
|
||||
|
||||
// sort composers
|
||||
var graph = new TopoGraph<Type, KeyValuePair<Type, List<Type>>>(kvp => kvp.Key, kvp => kvp.Value);
|
||||
graph.AddItems(requirements);
|
||||
List<Type> sortedComposerTypes;
|
||||
try
|
||||
{
|
||||
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).ToList();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// in case of an error, force-dump everything to log
|
||||
_logger.Info<Composers>("Composer Report:\r\n{ComposerReport}", GetComposersReport(requirements));
|
||||
_logger.Error<Composers>(e, "Failed to sort composers.");
|
||||
throw;
|
||||
}
|
||||
|
||||
// bit verbose but should help for troubleshooting
|
||||
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
|
||||
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
|
||||
|
||||
return sortedComposerTypes;
|
||||
}
|
||||
|
||||
private static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
text.AppendLine("Composers & Dependencies:");
|
||||
text.AppendLine();
|
||||
|
||||
foreach (var kvp in requirements)
|
||||
{
|
||||
var type = kvp.Key;
|
||||
|
||||
text.AppendLine(type.FullName);
|
||||
foreach (var attribute in type.GetCustomAttributes<ComposeAfterAttribute>())
|
||||
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
|
||||
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
|
||||
: ""));
|
||||
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
|
||||
text.AppendLine(" -< " + attribute.RequiringType);
|
||||
foreach (var i in type.GetInterfaces())
|
||||
{
|
||||
text.AppendLine(" : " + i.FullName);
|
||||
foreach (var attribute in i.GetCustomAttributes<ComposeAfterAttribute>())
|
||||
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
|
||||
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
|
||||
: ""));
|
||||
foreach (var attribute in i.GetCustomAttributes<ComposeBeforeAttribute>())
|
||||
text.AppendLine(" -< " + attribute.RequiringType);
|
||||
}
|
||||
if (kvp.Value != null)
|
||||
foreach (var t in kvp.Value)
|
||||
text.AppendLine(" = " + t);
|
||||
text.AppendLine();
|
||||
}
|
||||
text.AppendLine("/");
|
||||
text.AppendLine();
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
private static void EnableDisableComposers(ICollection<Type> types)
|
||||
{
|
||||
var enabled = new Dictionary<Type, EnableInfo>();
|
||||
|
||||
// process the enable/disable attributes
|
||||
// these two attributes are *not* inherited and apply to *classes* only (not interfaces).
|
||||
// remote declarations (when a composer enables/disables *another* composer)
|
||||
// have priority over local declarations (when a composer disables itself) so that
|
||||
// ppl can enable composers that, by default, are disabled.
|
||||
// what happens in case of conflicting remote declarations is unspecified. more
|
||||
// precisely, the last declaration to be processed wins, but the order of the
|
||||
// declarations depends on the type finder and is unspecified.
|
||||
foreach (var composerType in types)
|
||||
{
|
||||
foreach (var attr in composerType.GetCustomAttributes<EnableAttribute>())
|
||||
{
|
||||
var type = attr.EnabledType ?? composerType;
|
||||
if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo();
|
||||
var weight = type == composerType ? 1 : 2;
|
||||
if (enableInfo.Weight > weight) continue;
|
||||
|
||||
enableInfo.Enabled = true;
|
||||
enableInfo.Weight = weight;
|
||||
}
|
||||
foreach (var attr in composerType.GetCustomAttributes<DisableAttribute>())
|
||||
{
|
||||
var type = attr.DisabledType ?? composerType;
|
||||
if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo();
|
||||
var weight = type == composerType ? 1 : 2;
|
||||
if (enableInfo.Weight > weight) continue;
|
||||
|
||||
enableInfo.Enabled = false;
|
||||
enableInfo.Weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
// remove composers that end up being disabled
|
||||
foreach (var kvp in enabled.Where(x => x.Value.Enabled == false))
|
||||
types.Remove(kvp.Key);
|
||||
}
|
||||
|
||||
private static void GatherRequirementsFromRequireAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
// get 'require' attributes
|
||||
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
|
||||
var requireAttributes = type
|
||||
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeAfterAttribute>()) // those marking interfaces
|
||||
.Concat(type.GetCustomAttributes<ComposeAfterAttribute>()); // those marking the composer
|
||||
|
||||
// what happens in case of conflicting attributes (different strong/weak for same type) is not specified.
|
||||
foreach (var attr in requireAttributes)
|
||||
{
|
||||
if (attr.RequiredType == type) continue; // ignore self-requirements (+ exclude in implems, below)
|
||||
|
||||
// requiring an interface = require any enabled composer implementing that interface
|
||||
// unless strong, and then require at least one enabled composer implementing that interface
|
||||
if (attr.RequiredType.IsInterface)
|
||||
{
|
||||
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x)).ToList();
|
||||
if (implems.Count > 0)
|
||||
{
|
||||
if (requirements[type] == null) requirements[type] = new List<Type>();
|
||||
requirements[type].AddRange(implems);
|
||||
}
|
||||
else if (attr.Weak == false) // if explicitly set to !weak, is strong, else is weak
|
||||
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
|
||||
}
|
||||
// requiring a class = require that the composer is enabled
|
||||
// unless weak, and then requires it if it is enabled
|
||||
else
|
||||
{
|
||||
if (types.Contains(attr.RequiredType))
|
||||
{
|
||||
if (requirements[type] == null) requirements[type] = new List<Type>();
|
||||
requirements[type].Add(attr.RequiredType);
|
||||
}
|
||||
else if (attr.Weak != true) // if not explicitly set to weak, is strong
|
||||
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void GatherRequirementsFromRequiredByAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
// get 'required' attributes
|
||||
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
|
||||
var requiredAttributes = type
|
||||
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeBeforeAttribute>()) // those marking interfaces
|
||||
.Concat(type.GetCustomAttributes<ComposeBeforeAttribute>()); // those marking the composer
|
||||
|
||||
foreach (var attr in requiredAttributes)
|
||||
{
|
||||
if (attr.RequiringType == type) continue; // ignore self-requirements (+ exclude in implems, below)
|
||||
|
||||
// required by an interface = by any enabled composer implementing this that interface
|
||||
if (attr.RequiringType.IsInterface)
|
||||
{
|
||||
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x)).ToList();
|
||||
foreach (var implem in implems)
|
||||
{
|
||||
if (requirements[implem] == null) requirements[implem] = new List<Type>();
|
||||
requirements[implem].Add(type);
|
||||
}
|
||||
}
|
||||
// required by a class
|
||||
else
|
||||
{
|
||||
if (types.Contains(attr.RequiringType))
|
||||
{
|
||||
if (requirements[attr.RequiringType] == null) requirements[attr.RequiringType] = new List<Type>();
|
||||
requirements[attr.RequiringType].Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IComposer> InstantiateComposers(IEnumerable<Type> types)
|
||||
{
|
||||
IComposer InstantiateComposer(Type type)
|
||||
{
|
||||
var ctor = type.GetConstructor(Array.Empty<Type>());
|
||||
if (ctor == null)
|
||||
throw new InvalidOperationException($"Composer {type.FullName} does not have a parameter-less constructor.");
|
||||
return (IComposer) ctor.Invoke(Array.Empty<object>());
|
||||
}
|
||||
|
||||
using (_logger.DebugDuration<Composers>("Instantiating composers.", "Instantiated composers."))
|
||||
{
|
||||
return types.Select(InstantiateComposer).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using LightInject;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
@@ -14,206 +10,28 @@ namespace Umbraco.Core.Components
|
||||
/// avoid accessing the container. This is because everything needs to be properly registered and with
|
||||
/// the proper lifecycle. These methods will take care of it. Directly registering into the container
|
||||
/// may cause issues.</remarks>
|
||||
public class Composition : IRegister
|
||||
public class Composition
|
||||
{
|
||||
private readonly Dictionary<Type, ICollectionBuilder> _builders = new Dictionary<Type, ICollectionBuilder>();
|
||||
private readonly Dictionary<Type, Unique> _uniques = new Dictionary<Type, Unique>();
|
||||
private readonly IRegister _register;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Composition"/> class.
|
||||
/// </summary>
|
||||
/// <param name="register">A register.</param>
|
||||
/// <param name="typeLoader">A type loader.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
/// <param name="runtimeState">The runtime state.</param>
|
||||
/// <param name="configs">Optional configs.</param>
|
||||
public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs = null)
|
||||
/// <param name="container">A container.</param>
|
||||
/// <param name="level">The runtime level.</param>
|
||||
public Composition(IServiceContainer container, RuntimeLevel level)
|
||||
{
|
||||
_register = register;
|
||||
TypeLoader = typeLoader;
|
||||
Logger = logger;
|
||||
RuntimeState = runtimeState;
|
||||
|
||||
if (configs == null)
|
||||
{
|
||||
configs = new Configs();
|
||||
configs.AddCoreConfigs();
|
||||
}
|
||||
|
||||
Configs = configs;
|
||||
}
|
||||
|
||||
#region Services
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logger.
|
||||
/// </summary>
|
||||
public IProfilingLogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type loader.
|
||||
/// </summary>
|
||||
public TypeLoader TypeLoader { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runtime state.
|
||||
/// </summary>
|
||||
public IRuntimeState RuntimeState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configurations.
|
||||
/// </summary>
|
||||
public Configs Configs { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IRegister
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Concrete => _register.Concrete;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register(Type serviceType, Lifetime lifetime = Lifetime.Transient)
|
||||
=> _register.Register(serviceType, lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register(Type serviceType, Type implementingType, Lifetime lifetime = Lifetime.Transient)
|
||||
=> _register.Register(serviceType, implementingType, lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register<TService>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
||||
=> _register.Register(factory, lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterInstance(Type serviceType, object instance)
|
||||
=> _register.RegisterInstance(serviceType, instance);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterAuto(Type serviceBaseType)
|
||||
=> _register.RegisterAuto(serviceBaseType);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ConfigureForWeb()
|
||||
=> _register.ConfigureForWeb();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFactory CreateFactory()
|
||||
{
|
||||
foreach (var onCreating in OnCreatingFactory.Values)
|
||||
onCreating();
|
||||
|
||||
foreach (var unique in _uniques.Values)
|
||||
unique.RegisterWith(_register);
|
||||
|
||||
foreach (var builder in _builders.Values)
|
||||
builder.RegisterWith(_register);
|
||||
|
||||
Configs.RegisterWith(_register);
|
||||
|
||||
return _register.CreateFactory();
|
||||
Container = container;
|
||||
RuntimeLevel = level;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of action to execute when creating the factory.
|
||||
/// Gets the container.
|
||||
/// </summary>
|
||||
public Dictionary<string, Action> OnCreatingFactory { get; } = new Dictionary<string, Action>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unique
|
||||
/// <remarks>Use with care!</remarks>
|
||||
public IServiceContainer Container { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service.
|
||||
/// Gets the runtime level.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique(Type serviceType, Type implementingType)
|
||||
=> _uniques[serviceType] = new Unique(serviceType, implementingType);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique(Type serviceType, object instance)
|
||||
=> _uniques[serviceType] = new Unique(serviceType, instance);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique<TService>(Func<IFactory, TService> factory)
|
||||
=> _uniques[typeof(TService)] = new Unique<TService>(factory);
|
||||
|
||||
private class Unique
|
||||
{
|
||||
private readonly Type _serviceType;
|
||||
private readonly Type _implementingType;
|
||||
private readonly object _instance;
|
||||
|
||||
protected Unique(Type serviceType)
|
||||
{
|
||||
_serviceType = serviceType;
|
||||
}
|
||||
|
||||
public Unique(Type serviceType, Type implementingType)
|
||||
: this(serviceType)
|
||||
{
|
||||
_implementingType = implementingType;
|
||||
}
|
||||
|
||||
public Unique(Type serviceType, object instance)
|
||||
: this(serviceType)
|
||||
{
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
public virtual void RegisterWith(IRegister register)
|
||||
{
|
||||
if (_implementingType != null)
|
||||
register.Register(_serviceType, _implementingType, Lifetime.Singleton);
|
||||
else if (_instance != null)
|
||||
register.RegisterInstance(_serviceType, _instance);
|
||||
}
|
||||
}
|
||||
|
||||
private class Unique<TService> : Unique
|
||||
{
|
||||
private readonly Func<IFactory, TService> _factory;
|
||||
|
||||
public Unique(Func<IFactory, TService> factory)
|
||||
: base(typeof(TService))
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public override void RegisterWith(IRegister register)
|
||||
{
|
||||
register.Register(_factory, Lifetime.Singleton);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Collection Builders
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection builder (and registers the collection).
|
||||
/// </summary>
|
||||
/// <typeparam name="TBuilder">The type of the collection builder.</typeparam>
|
||||
/// <returns>The collection builder.</returns>
|
||||
public TBuilder WithCollectionBuilder<TBuilder>()
|
||||
where TBuilder: ICollectionBuilder, new()
|
||||
{
|
||||
var typeOfBuilder = typeof(TBuilder);
|
||||
|
||||
if (_builders.TryGetValue(typeOfBuilder, out var o))
|
||||
return (TBuilder) o;
|
||||
|
||||
var builder = new TBuilder();
|
||||
_builders[typeOfBuilder] = builder;
|
||||
return builder;
|
||||
}
|
||||
|
||||
#endregion
|
||||
public RuntimeLevel RuntimeLevel { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Migrations;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
@@ -18,45 +19,6 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
public static class CompositionExtensions
|
||||
{
|
||||
#region FileSystems
|
||||
|
||||
/// <summary>
|
||||
/// Registers a filesystem.
|
||||
/// </summary>
|
||||
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
|
||||
/// <typeparam name="TImplementing">The implementing type.</typeparam>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="supportingFileSystemFactory">A factory method creating the supporting filesystem.</param>
|
||||
/// <returns>The register.</returns>
|
||||
public static void RegisterFileSystem<TFileSystem, TImplementing>(this Composition composition, Func<IFactory, IFileSystem> supportingFileSystemFactory)
|
||||
where TImplementing : FileSystemWrapper, TFileSystem
|
||||
{
|
||||
composition.RegisterUnique<TFileSystem>(factory =>
|
||||
{
|
||||
var fileSystems = factory.GetInstance<FileSystems>();
|
||||
return fileSystems.GetFileSystem<TImplementing>(supportingFileSystemFactory(factory));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a filesystem.
|
||||
/// </summary>
|
||||
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="supportingFileSystemFactory">A factory method creating the supporting filesystem.</param>
|
||||
/// <returns>The register.</returns>
|
||||
public static void RegisterFileSystem<TFileSystem>(this Composition composition, Func<IFactory, IFileSystem> supportingFileSystemFactory)
|
||||
where TFileSystem : FileSystemWrapper
|
||||
{
|
||||
composition.RegisterUnique(factory =>
|
||||
{
|
||||
var fileSystems = factory.GetInstance<FileSystems>();
|
||||
return fileSystems.GetFileSystem<TFileSystem>(supportingFileSystemFactory(factory));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Collection Builders
|
||||
|
||||
/// <summary>
|
||||
@@ -64,66 +26,60 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static CacheRefresherCollectionBuilder CacheRefreshers(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<CacheRefresherCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<CacheRefresherCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mappers collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static MapperCollectionBuilder Mappers(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<MapperCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<MapperCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the package actions collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
internal static PackageActionCollectionBuilder PackageActions(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<PackageActionCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<PackageActionCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data editor collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static DataEditorCollectionBuilder DataEditors(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<DataEditorCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<DataEditorCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property value converters collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<PropertyValueConverterCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<PropertyValueConverterCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url segment providers collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<UrlSegmentProviderCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<UrlSegmentProviderCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the validators collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
internal static ManifestValueValidatorCollectionBuilder Validators(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<ManifestValueValidatorCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the post-migrations collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
internal static PostMigrationCollectionBuilder PostMigrations(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<PostMigrationCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the components collection builder.
|
||||
/// </summary>
|
||||
public static ComponentCollectionBuilder Components(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<ComponentCollectionBuilder>();
|
||||
=> composition.Container.GetInstance<PostMigrationCollectionBuilder>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Uniques
|
||||
#region Singleton
|
||||
|
||||
/// <summary>
|
||||
/// Sets the culture dictionary factory.
|
||||
@@ -133,7 +89,7 @@ namespace Umbraco.Core.Components
|
||||
public static void SetCultureDictionaryFactory<T>(this Composition composition)
|
||||
where T : ICultureDictionaryFactory
|
||||
{
|
||||
composition.RegisterUnique<ICultureDictionaryFactory, T>();
|
||||
composition.Container.RegisterSingleton<ICultureDictionaryFactory, T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -141,9 +97,9 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="factory">A function creating a culture dictionary factory.</param>
|
||||
public static void SetCultureDictionaryFactory(this Composition composition, Func<IFactory, ICultureDictionaryFactory> factory)
|
||||
public static void SetCultureDictionaryFactory(this Composition composition, Func<IServiceFactory, ICultureDictionaryFactory> factory)
|
||||
{
|
||||
composition.RegisterUnique(factory);
|
||||
composition.Container.RegisterSingleton(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -153,7 +109,7 @@ namespace Umbraco.Core.Components
|
||||
/// <param name="factory">A factory.</param>
|
||||
public static void SetCultureDictionaryFactory(this Composition composition, ICultureDictionaryFactory factory)
|
||||
{
|
||||
composition.RegisterUnique(_ => factory);
|
||||
composition.Container.RegisterSingleton(_ => factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -164,7 +120,7 @@ namespace Umbraco.Core.Components
|
||||
public static void SetPublishedContentModelFactory<T>(this Composition composition)
|
||||
where T : IPublishedModelFactory
|
||||
{
|
||||
composition.RegisterUnique<IPublishedModelFactory, T>();
|
||||
composition.Container.RegisterSingleton<IPublishedModelFactory, T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,9 +128,9 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="factory">A function creating a published content model factory.</param>
|
||||
public static void SetPublishedContentModelFactory(this Composition composition, Func<IFactory, IPublishedModelFactory> factory)
|
||||
public static void SetPublishedContentModelFactory(this Composition composition, Func<IServiceFactory, IPublishedModelFactory> factory)
|
||||
{
|
||||
composition.RegisterUnique(factory);
|
||||
composition.Container.RegisterSingleton(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -184,7 +140,7 @@ namespace Umbraco.Core.Components
|
||||
/// <param name="factory">A published content model factory.</param>
|
||||
public static void SetPublishedContentModelFactory(this Composition composition, IPublishedModelFactory factory)
|
||||
{
|
||||
composition.RegisterUnique(_ => factory);
|
||||
composition.Container.RegisterSingleton(_ => factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -195,7 +151,7 @@ namespace Umbraco.Core.Components
|
||||
public static void SetServerRegistrar<T>(this Composition composition)
|
||||
where T : IServerRegistrar
|
||||
{
|
||||
composition.RegisterUnique<IServerRegistrar, T>();
|
||||
composition.Container.RegisterSingleton<IServerRegistrar, T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -203,9 +159,9 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="factory">A function creating a server registar.</param>
|
||||
public static void SetServerRegistrar(this Composition composition, Func<IFactory, IServerRegistrar> factory)
|
||||
public static void SetServerRegistrar(this Composition composition, Func<IServiceFactory, IServerRegistrar> factory)
|
||||
{
|
||||
composition.RegisterUnique(factory);
|
||||
composition.Container.RegisterSingleton(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -215,7 +171,7 @@ namespace Umbraco.Core.Components
|
||||
/// <param name="registrar">A server registrar.</param>
|
||||
public static void SetServerRegistrar(this Composition composition, IServerRegistrar registrar)
|
||||
{
|
||||
composition.RegisterUnique(_ => registrar);
|
||||
composition.Container.RegisterSingleton(_ => registrar);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -226,7 +182,7 @@ namespace Umbraco.Core.Components
|
||||
public static void SetServerMessenger<T>(this Composition composition)
|
||||
where T : IServerMessenger
|
||||
{
|
||||
composition.RegisterUnique<IServerMessenger, T>();
|
||||
composition.Container.RegisterSingleton<IServerMessenger, T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -234,9 +190,9 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="factory">A function creating a server messenger.</param>
|
||||
public static void SetServerMessenger(this Composition composition, Func<IFactory, IServerMessenger> factory)
|
||||
public static void SetServerMessenger(this Composition composition, Func<IServiceFactory, IServerMessenger> factory)
|
||||
{
|
||||
composition.RegisterUnique(factory);
|
||||
composition.Container.RegisterSingleton(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -246,7 +202,7 @@ namespace Umbraco.Core.Components
|
||||
/// <param name="registrar">A server messenger.</param>
|
||||
public static void SetServerMessenger(this Composition composition, IServerMessenger registrar)
|
||||
{
|
||||
composition.RegisterUnique(_ => registrar);
|
||||
composition.Container.RegisterSingleton(_ => registrar);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -257,7 +213,7 @@ namespace Umbraco.Core.Components
|
||||
public static void SetShortStringHelper<T>(this Composition composition)
|
||||
where T : IShortStringHelper
|
||||
{
|
||||
composition.RegisterUnique<IShortStringHelper, T>();
|
||||
composition.Container.RegisterSingleton<IShortStringHelper, T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -265,9 +221,9 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="factory">A function creating a short string helper.</param>
|
||||
public static void SetShortStringHelper(this Composition composition, Func<IFactory, IShortStringHelper> factory)
|
||||
public static void SetShortStringHelper(this Composition composition, Func<IServiceFactory, IShortStringHelper> factory)
|
||||
{
|
||||
composition.RegisterUnique(factory);
|
||||
composition.Container.RegisterSingleton(factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -277,7 +233,7 @@ namespace Umbraco.Core.Components
|
||||
/// <param name="helper">A short string helper.</param>
|
||||
public static void SetShortStringHelper(this Composition composition, IShortStringHelper helper)
|
||||
{
|
||||
composition.RegisterUnique(_ => helper);
|
||||
composition.Container.RegisterSingleton(_ => helper);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer should be disabled.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If a type is specified, disables the composer of that type, else disables the composer marked with the attribute.</para>
|
||||
/// <para>This attribute is *not* inherited.</para>
|
||||
/// <para>This attribute applies to classes only, it is not possible to enable/disable interfaces.</para>
|
||||
/// <para>If a composer ends up being both enabled and disabled: attributes marking the composer itself have lower priority
|
||||
/// than attributes on *other* composers, eg if a composer declares itself as disabled it is possible to enable it from
|
||||
/// another composer. Anything else is unspecified.</para>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public class DisableAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DisableAttribute"/> class.
|
||||
/// </summary>
|
||||
public DisableAttribute()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DisableAttribute"/> class.
|
||||
/// </summary>
|
||||
public DisableAttribute(Type disabledType)
|
||||
{
|
||||
DisabledType = disabledType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the disabled type, or null if it is the composer marked with the attribute.
|
||||
/// </summary>
|
||||
public Type DisabledType { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a component should be disabled.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If a type is specified, disables the component of that type, else disables the component marked with the attribute.</para>
|
||||
/// <para>This attribute is *not* inherited.</para>
|
||||
/// <para>This attribute applies to classes only, it is not possible to enable/disable interfaces.</para>
|
||||
/// <para>If a component ends up being both enabled and disabled: attributes marking the component itself have lower priority
|
||||
/// than attributes on *other* components, eg if a component declares itself as disabled it is possible to enable it from
|
||||
/// another component. Anything else is unspecified.</para>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public class DisableComponentAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DisableComponentAttribute"/> class.
|
||||
/// </summary>
|
||||
public DisableComponentAttribute()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DisableComponentAttribute"/> class.
|
||||
/// </summary>
|
||||
public DisableComponentAttribute(Type disabledType)
|
||||
{
|
||||
DisabledType = disabledType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the disabled type, or null if it is the component marked with the attribute.
|
||||
/// </summary>
|
||||
public Type DisabledType { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer should be enabled.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If a type is specified, enables the composer of that type, else enables the composer marked with the attribute.</para>
|
||||
/// <para>This attribute is *not* inherited.</para>
|
||||
/// <para>This attribute applies to classes only, it is not possible to enable/disable interfaces.</para>
|
||||
/// <para>If a composer ends up being both enabled and disabled: attributes marking the composer itself have lower priority
|
||||
/// than attributes on *other* composers, eg if a composer declares itself as disabled it is possible to enable it from
|
||||
/// another composer. Anything else is unspecified.</para>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public class EnableAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnableAttribute"/> class.
|
||||
/// </summary>
|
||||
public EnableAttribute()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnableAttribute"/> class.
|
||||
/// </summary>
|
||||
public EnableAttribute(Type enabledType)
|
||||
{
|
||||
EnabledType = enabledType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the enabled type, or null if it is the composer marked with the attribute.
|
||||
/// </summary>
|
||||
public Type EnabledType { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a component should be enabled.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If a type is specified, enables the component of that type, else enables the component marked with the attribute.</para>
|
||||
/// <para>This attribute is *not* inherited.</para>
|
||||
/// <para>This attribute applies to classes only, it is not possible to enable/disable interfaces.</para>
|
||||
/// <para>If a component ends up being both enabled and disabled: attributes marking the component itself have lower priority
|
||||
/// than attributes on *other* components, eg if a component declares itself as disabled it is possible to enable it from
|
||||
/// another component. Anything else is unspecified.</para>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public class EnableComponentAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnableComponentAttribute"/> class.
|
||||
/// </summary>
|
||||
public EnableComponentAttribute()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnableComponentAttribute"/> class.
|
||||
/// </summary>
|
||||
public EnableComponentAttribute(Type enabledType)
|
||||
{
|
||||
EnabledType = enabledType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the enabled type, or null if it is the component marked with the attribute.
|
||||
/// </summary>
|
||||
public Type EnabledType { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a component.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Components are created by DI and therefore must have a public constructor.</para>
|
||||
/// <para>All components are terminated in reverse order when Umbraco terminates, and
|
||||
/// disposable components are disposed.</para>
|
||||
/// <para>The Dispose method may be invoked more than once, and components
|
||||
/// should ensure they support this.</para>
|
||||
/// </remarks>
|
||||
public interface IComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the component.
|
||||
/// </summary>
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Terminates the component.
|
||||
/// </summary>
|
||||
void Terminate();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a composer.
|
||||
/// </summary>
|
||||
public interface IComposer : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Compose.
|
||||
/// </summary>
|
||||
/// <param name="composition"></param>
|
||||
void Compose(Composition composition);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a core <see cref="IComposer"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>All core composers are required by (compose before) all user composers,
|
||||
/// and require (compose after) all runtime composers.</para>
|
||||
/// </remarks>
|
||||
[ComposeAfter(typeof(IRuntimeComposer))]
|
||||
public interface ICoreComposer : IComposer
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
public interface IRuntimeComponent : IUmbracoComponent
|
||||
{ }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a runtime <see cref="IComposer"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>All runtime composers are required by (compose before) all core composers</para>
|
||||
/// </remarks>
|
||||
public interface IRuntimeComposer : IComposer
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an Umbraco component.
|
||||
/// </summary>
|
||||
public interface IUmbracoComponent : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Composes the component.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
void Compose(Composition composition);
|
||||
|
||||
/// <summary>
|
||||
/// Terminates the component.
|
||||
/// </summary>
|
||||
void Terminate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
[RequireComponent(typeof(IRuntimeComponent))]
|
||||
public interface IUmbracoCoreComponent : IUmbracoComponent
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
[RequireComponent(typeof(UmbracoCoreComponent))]
|
||||
public interface IUmbracoUserComponent : IUmbracoComponent
|
||||
{ }
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user <see cref="IComposer"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>All user composers require (compose after) all core composers.</para>
|
||||
/// </remarks>
|
||||
[ComposeAfter(typeof(ICoreComposer))]
|
||||
public interface IUserComposer : IComposer
|
||||
{ }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
|
||||
public class ManifestWatcherComposer : ComponentComposer<ManifestWatcherComponent>, ICoreComposer
|
||||
{ }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
|
||||
public sealed class RelateOnCopyComposer : ComponentComposer<RelateOnCopyComponent>, ICoreComposer
|
||||
{ }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
|
||||
public sealed class RelateOnTrashComposer : ComponentComposer<RelateOnTrashComponent>, ICoreComposer
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a component requires another component.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This attribute is *not* inherited. This means that a component class inheriting from
|
||||
/// another component class does *not* inherit its requirements. However, the bootloader checks
|
||||
/// the *interfaces* of every component for their requirements, so requirements declared on
|
||||
/// interfaces are inherited by every component class implementing the interface.</para>
|
||||
/// <para>When targetting a class, indicates a dependency on the component which must be enabled,
|
||||
/// unless the requirement has explicitely been declared as weak (and then, only if the component
|
||||
/// is enabled).</para>
|
||||
/// <para>When targetting an interface, indicates a dependency on enabled components implementing
|
||||
/// the interface. It could be no component at all, unless the requirement has explicitely been
|
||||
/// declared as strong (and at least one component must be enabled).</para>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
|
||||
public class RequireComponentAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequireComponentAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredType">The type of the required component.</param>
|
||||
public RequireComponentAttribute(Type requiredType)
|
||||
{
|
||||
if (typeof(IUmbracoComponent).IsAssignableFrom(requiredType) == false)
|
||||
throw new ArgumentException($"Type {requiredType.FullName} is invalid here because it does not implement {typeof(IUmbracoComponent).FullName}.");
|
||||
RequiredType = requiredType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequireComponentAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiredType">The type of the required component.</param>
|
||||
/// <param name="weak">A value indicating whether the requirement is weak.</param>
|
||||
public RequireComponentAttribute(Type requiredType, bool weak)
|
||||
: this(requiredType)
|
||||
{
|
||||
Weak = weak;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the required type.
|
||||
/// </summary>
|
||||
public Type RequiredType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the requirement is weak.
|
||||
/// </summary>
|
||||
/// <remarks>Returns <c>true</c> if the requirement is weak (requires the other component if it
|
||||
/// is enabled), <c>false</c> if the requirement is strong (requires the other component to be
|
||||
/// enabled), and <c>null</c> if unspecified, in which case it is strong for classes and weak for
|
||||
/// interfaces.</remarks>
|
||||
public bool? Weak { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a component is required by another component.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// fixme
|
||||
/// <para>This attribute is *not* inherited. This means that a component class inheriting from
|
||||
/// another component class does *not* inherit its requirements. However, the bootloader checks
|
||||
/// the *interfaces* of every component for their requirements, so requirements declared on
|
||||
/// interfaces are inherited by every component class implementing the interface.</para>
|
||||
/// <para>When targetting a class, indicates a dependency on the component which must be enabled,
|
||||
/// unless the requirement has explicitely been declared as weak (and then, only if the component
|
||||
/// is enabled).</para>
|
||||
/// <para>When targetting an interface, indicates a dependency on enabled components implementing
|
||||
/// the interface. It could be no component at all, unless the requirement has explicitely been
|
||||
/// declared as strong (and at least one component must be enabled).</para>
|
||||
/// </remarks>
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
|
||||
public class RequiredComponentAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequiredComponentAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="requiringType">The type of the required component.</param>
|
||||
public RequiredComponentAttribute(Type requiringType)
|
||||
{
|
||||
if (typeof(IUmbracoComponent).IsAssignableFrom(requiringType) == false)
|
||||
throw new ArgumentException($"Type {requiringType.FullName} is invalid here because it does not implement {typeof(IUmbracoComponent).FullName}.");
|
||||
RequiringType = requiringType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the required type.
|
||||
/// </summary>
|
||||
public Type RequiringType { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for <see cref="IUmbracoComponent"/> implementations.
|
||||
/// </summary>
|
||||
public abstract class UmbracoComponentBase : IUmbracoComponent
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public virtual void Compose(Composition composition)
|
||||
{ }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void Terminate()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Core.Components
|
||||
{
|
||||
// the UmbracoCoreComponent requires all IUmbracoCoreComponent
|
||||
// all user-level components should require the UmbracoCoreComponent
|
||||
|
||||
[RequireComponent(typeof(IUmbracoCoreComponent))]
|
||||
public class UmbracoCoreComponent : UmbracoComponentBase
|
||||
{ }
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using LightInject;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
@@ -16,30 +18,65 @@ namespace Umbraco.Core.Composing
|
||||
{
|
||||
private readonly List<Type> _types = new List<Type>();
|
||||
private readonly object _locker = new object();
|
||||
private Type[] _registeredTypes;
|
||||
private Func<IEnumerable<TItem>, TCollection> _collectionCtor;
|
||||
private ServiceRegistration[] _registrations;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CollectionBuilderBase{TBuilder, TCollection,TItem}"/>
|
||||
/// class with a service container.
|
||||
/// </summary>
|
||||
/// <param name="container">A service container.</param>
|
||||
protected CollectionBuilderBase(IServiceContainer container)
|
||||
{
|
||||
Container = container;
|
||||
// ReSharper disable once DoNotCallOverridableMethodsInConstructor
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service container.
|
||||
/// </summary>
|
||||
protected IServiceContainer Container { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal list of types as an IEnumerable (immutable).
|
||||
/// </summary>
|
||||
public IEnumerable<Type> GetTypes() => _types;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void RegisterWith(IRegister register)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the builder.
|
||||
/// </summary>
|
||||
/// <remarks>This is called by the constructor and, by default, registers the
|
||||
/// collection automatically.</remarks>
|
||||
protected virtual void Initialize()
|
||||
{
|
||||
if (_registeredTypes != null)
|
||||
throw new InvalidOperationException("This builder has already been registered.");
|
||||
// compile the auto-collection constructor
|
||||
var argType = typeof(IEnumerable<TItem>);
|
||||
var ctorArgTypes = new[] { argType };
|
||||
var constructor = typeof(TCollection).GetConstructor(ctorArgTypes);
|
||||
if (constructor != null)
|
||||
{
|
||||
var exprArg = Expression.Parameter(argType, "items");
|
||||
var exprNew = Expression.New(constructor, exprArg);
|
||||
var expr = Expression.Lambda<Func<IEnumerable<TItem>, TCollection>>(exprNew, exprArg);
|
||||
_collectionCtor = expr.Compile();
|
||||
}
|
||||
// else _collectionCtor remains null, assuming CreateCollection has been overriden
|
||||
|
||||
// we just don't want to support re-registering collections here
|
||||
var registration = Container.GetAvailableService<TCollection>();
|
||||
if (registration != null)
|
||||
throw new InvalidOperationException("Collection builders cannot be registered once the collection itself has been registered.");
|
||||
|
||||
// register the collection
|
||||
register.Register(CreateCollection, CollectionLifetime);
|
||||
|
||||
// register the types
|
||||
RegisterTypes(register);
|
||||
Container.Register(_ => CreateCollection(), CollectionLifetime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection lifetime.
|
||||
/// </summary>
|
||||
protected virtual Lifetime CollectionLifetime => Lifetime.Singleton;
|
||||
/// <remarks>Return null for transient collections.</remarks>
|
||||
protected virtual ILifetime CollectionLifetime => new PerContainerLifetime();
|
||||
|
||||
/// <summary>
|
||||
/// Configures the internal list of types.
|
||||
@@ -50,8 +87,8 @@ namespace Umbraco.Core.Composing
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_registeredTypes != null)
|
||||
throw new InvalidOperationException("Cannot configure a collection builder after it has been registered.");
|
||||
if (_registrations != null)
|
||||
throw new InvalidOperationException("Cannot configure a collection builder after its types have been resolved.");
|
||||
action(_types);
|
||||
}
|
||||
}
|
||||
@@ -67,54 +104,55 @@ namespace Umbraco.Core.Composing
|
||||
return types;
|
||||
}
|
||||
|
||||
private void RegisterTypes(IRegister register)
|
||||
private void RegisterTypes()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_registeredTypes != null) return;
|
||||
if (_registrations != null) return;
|
||||
|
||||
var types = GetRegisteringTypes(_types).ToArray();
|
||||
|
||||
// ensure they are safe
|
||||
foreach (var type in types)
|
||||
EnsureType(type, "register");
|
||||
|
||||
// register them
|
||||
var prefix = GetType().FullName + "_";
|
||||
var i = 0;
|
||||
foreach (var type in types)
|
||||
register.Register(type);
|
||||
{
|
||||
var name = $"{prefix}{i++:00000}";
|
||||
Container.Register(typeof(TItem), type, name);
|
||||
}
|
||||
|
||||
_registeredTypes = types;
|
||||
_registrations = Container.AvailableServices
|
||||
.Where(x => x.ServiceName.StartsWith(prefix))
|
||||
.OrderBy(x => x.ServiceName)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the collection items.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
/// <returns>The collection items.</returns>
|
||||
protected virtual IEnumerable<TItem> CreateItems(IFactory factory)
|
||||
protected virtual IEnumerable<TItem> CreateItems(params object[] args)
|
||||
{
|
||||
if (_registeredTypes == null)
|
||||
throw new InvalidOperationException("Cannot create items before the collection builder has been registered.");
|
||||
RegisterTypes(); // will do it only once
|
||||
|
||||
return _registeredTypes // respect order
|
||||
.Select(x => CreateItem(factory, x))
|
||||
var type = typeof (TItem);
|
||||
return _registrations
|
||||
.Select(x => (TItem) Container.GetInstanceOrThrow(type, x.ServiceName, x.ImplementingType, args))
|
||||
.ToArray(); // safe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a collection item.
|
||||
/// </summary>
|
||||
protected virtual TItem CreateItem(IFactory factory, Type itemType)
|
||||
=> (TItem) factory.GetInstance(itemType);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a collection.
|
||||
/// </summary>
|
||||
/// <returns>A collection.</returns>
|
||||
/// <remarks>Creates a new collection each time it is invoked.</remarks>
|
||||
public virtual TCollection CreateCollection(IFactory factory)
|
||||
public virtual TCollection CreateCollection()
|
||||
{
|
||||
return factory.CreateInstance<TCollection>(CreateItems(factory));
|
||||
if (_collectionCtor == null) throw new InvalidOperationException("Collection auto-creation is not possible.");
|
||||
return _collectionCtor(CreateItems());
|
||||
}
|
||||
|
||||
protected Type EnsureType(Type type, string action)
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
|
||||
namespace Umbraco.Core.Composing.Composers
|
||||
{
|
||||
/// <summary>
|
||||
/// Compose configurations.
|
||||
/// </summary>
|
||||
public static class ConfigurationComposer
|
||||
{
|
||||
public static Composition ComposeConfiguration(this Composition composition)
|
||||
{
|
||||
// common configurations are already registered
|
||||
// register others
|
||||
|
||||
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoSettingsSection>().Content);
|
||||
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoSettingsSection>().Templates);
|
||||
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoSettingsSection>().RequestHandler);
|
||||
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoSettingsSection>().Security);
|
||||
|
||||
return composition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Composing.Composers
|
||||
|
||||
{
|
||||
public static class CoreMappingProfilesComposer
|
||||
{
|
||||
public static Composition ComposeCoreMappingProfiles(this Composition composition)
|
||||
{
|
||||
composition.Register<Profile, IdentityMapperProfile>();
|
||||
return composition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.IO.MediaPathSchemes;
|
||||
|
||||
namespace Umbraco.Core.Composing.Composers
|
||||
{
|
||||
public static class FileSystemsComposer
|
||||
{
|
||||
/*
|
||||
* HOW TO REPLACE THE MEDIA UNDERLYING FILESYSTEM
|
||||
* ----------------------------------------------
|
||||
*
|
||||
* Create a component and use it to modify the composition by adding something like:
|
||||
*
|
||||
* composition.Container.RegisterFileSystem<IMediaFileSystem, MediaFileSystem>(
|
||||
* factory => new PhysicalFileSystem("~/somewhere"));
|
||||
*
|
||||
* return whatever supporting filesystem you like.
|
||||
*
|
||||
*
|
||||
* HOW TO IMPLEMENT MY OWN FILESYSTEM
|
||||
* ----------------------------------
|
||||
*
|
||||
* Create your filesystem class:
|
||||
*
|
||||
* public class MyFileSystem : FileSystemWrapper
|
||||
* {
|
||||
* public MyFileSystem(IFileSystem innerFileSystem)
|
||||
* : base(innerFileSystem)
|
||||
* { }
|
||||
* }
|
||||
*
|
||||
* The ctor can have more parameters that will be resolved by the container.
|
||||
*
|
||||
* Register your filesystem, in a component:
|
||||
*
|
||||
* composition.Container.RegisterFileSystem<MyFileSystem>(
|
||||
* factory => new PhysicalFileSystem("~/my"));
|
||||
*
|
||||
* And that's it, you can inject MyFileSystem wherever it's needed.
|
||||
*
|
||||
*
|
||||
* You can also declare a filesystem interface:
|
||||
*
|
||||
* public interface IMyFileSystem : IFileSystem
|
||||
* { }
|
||||
*
|
||||
* Make the class implement the interface, then
|
||||
* register your filesystem, in a component:
|
||||
*
|
||||
* composition.Container.RegisterFileSystem<IMyFileSystem, MyFileSystem>(
|
||||
* factory => new PhysicalFileSystem("~/my"));
|
||||
*
|
||||
* And that's it, you can inject IMyFileSystem wherever it's needed.
|
||||
*
|
||||
*
|
||||
* WHAT IS SHADOWING
|
||||
* -----------------
|
||||
*
|
||||
* Shadowing is the technology used for Deploy to implement some sort of
|
||||
* transaction-management on top of filesystems. The plumbing explained above,
|
||||
* compared to creating your own physical filesystem, ensures that your filesystem
|
||||
* would participate into such transactions.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
public static Composition ComposeFileSystems(this Composition composition)
|
||||
{
|
||||
// register FileSystems, which manages all filesystems
|
||||
// it needs to be registered (not only the interface) because it provides additional
|
||||
// functionality eg for scoping, and is injected in the scope provider - whereas the
|
||||
// interface is really for end-users to get access to filesystems.
|
||||
composition.RegisterUnique(factory => factory.CreateInstance<FileSystems>(factory));
|
||||
|
||||
// register IFileSystems, which gives access too all filesystems
|
||||
composition.RegisterUnique<IFileSystems>(factory => factory.GetInstance<FileSystems>());
|
||||
|
||||
// register the scheme for media paths
|
||||
composition.RegisterUnique<IMediaPathScheme, TwoGuidsMediaPathScheme>();
|
||||
|
||||
// register the IMediaFileSystem implementation with a supporting filesystem
|
||||
composition.RegisterFileSystem<IMediaFileSystem, MediaFileSystem>(
|
||||
factory => new PhysicalFileSystem("~/media"));
|
||||
|
||||
return composition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
|
||||
namespace Umbraco.Core.Composing.Composers
|
||||
{
|
||||
/// <summary>
|
||||
/// Composes repositories.
|
||||
/// </summary>
|
||||
public static class RepositoriesComposer
|
||||
{
|
||||
public static Composition ComposeRepositories(this Composition composition)
|
||||
{
|
||||
// repositories
|
||||
composition.RegisterUnique<IAuditRepository, AuditRepository>();
|
||||
composition.RegisterUnique<IAuditEntryRepository, AuditEntryRepository>();
|
||||
composition.RegisterUnique<IContentTypeRepository, ContentTypeRepository>();
|
||||
composition.RegisterUnique<IDataTypeContainerRepository, DataTypeContainerRepository>();
|
||||
composition.RegisterUnique<IDataTypeRepository, DataTypeRepository>();
|
||||
composition.RegisterUnique<IDictionaryRepository, DictionaryRepository>();
|
||||
composition.RegisterUnique<IDocumentBlueprintRepository, DocumentBlueprintRepository>();
|
||||
composition.RegisterUnique<IDocumentRepository, DocumentRepository>();
|
||||
composition.RegisterUnique<IDocumentTypeContainerRepository, DocumentTypeContainerRepository>();
|
||||
composition.RegisterUnique<IDomainRepository, DomainRepository>();
|
||||
composition.RegisterUnique<IEntityRepository, EntityRepository>();
|
||||
composition.RegisterUnique<IExternalLoginRepository, ExternalLoginRepository>();
|
||||
composition.RegisterUnique<ILanguageRepository, LanguageRepository>();
|
||||
composition.RegisterUnique<IMacroRepository, MacroRepository>();
|
||||
composition.RegisterUnique<IMediaRepository, MediaRepository>();
|
||||
composition.RegisterUnique<IMediaTypeContainerRepository, MediaTypeContainerRepository>();
|
||||
composition.RegisterUnique<IMediaTypeRepository, MediaTypeRepository>();
|
||||
composition.RegisterUnique<IMemberGroupRepository, MemberGroupRepository>();
|
||||
composition.RegisterUnique<IMemberRepository, MemberRepository>();
|
||||
composition.RegisterUnique<IMemberTypeRepository, MemberTypeRepository>();
|
||||
composition.RegisterUnique<INotificationsRepository, NotificationsRepository>();
|
||||
composition.RegisterUnique<IPublicAccessRepository, PublicAccessRepository>();
|
||||
composition.RegisterUnique<IRedirectUrlRepository, RedirectUrlRepository>();
|
||||
composition.RegisterUnique<IRelationRepository, RelationRepository>();
|
||||
composition.RegisterUnique<IRelationTypeRepository, RelationTypeRepository>();
|
||||
composition.RegisterUnique<IServerRegistrationRepository, ServerRegistrationRepository>();
|
||||
composition.RegisterUnique<ITagRepository, TagRepository>();
|
||||
composition.RegisterUnique<ITemplateRepository, TemplateRepository>();
|
||||
composition.RegisterUnique<IUserGroupRepository, UserGroupRepository>();
|
||||
composition.RegisterUnique<IUserRepository, UserRepository>();
|
||||
composition.RegisterUnique<IConsentRepository, ConsentRepository>();
|
||||
composition.RegisterUnique<IPartialViewMacroRepository, PartialViewMacroRepository>();
|
||||
composition.RegisterUnique<IPartialViewRepository, PartialViewRepository>();
|
||||
composition.RegisterUnique<IScriptRepository, ScriptRepository>();
|
||||
composition.RegisterUnique<IStylesheetRepository, StylesheetRepository>();
|
||||
|
||||
return composition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Core.Composing.Composers
|
||||
{
|
||||
public static class ServicesComposer
|
||||
{
|
||||
public static Composition ComposeServices(this Composition composition)
|
||||
{
|
||||
// register a transient messages factory, which will be replaced by the web
|
||||
// boot manager when running in a web context
|
||||
composition.RegisterUnique<IEventMessagesFactory, TransientEventMessagesFactory>();
|
||||
|
||||
// register the service context
|
||||
composition.RegisterUnique<ServiceContext>();
|
||||
|
||||
// register the special idk map
|
||||
composition.RegisterUnique<IdkMap>();
|
||||
|
||||
// register the services
|
||||
composition.RegisterUnique<IKeyValueService, KeyValueService>();
|
||||
composition.RegisterUnique<IPublicAccessService, PublicAccessService>();
|
||||
composition.RegisterUnique<IDomainService, DomainService>();
|
||||
composition.RegisterUnique<IAuditService, AuditService>();
|
||||
composition.RegisterUnique<ITagService, TagService>();
|
||||
composition.RegisterUnique<IContentService, ContentService>();
|
||||
composition.RegisterUnique<IUserService, UserService>();
|
||||
composition.RegisterUnique<IMemberService, MemberService>();
|
||||
composition.RegisterUnique<IMediaService, MediaService>();
|
||||
composition.RegisterUnique<IContentTypeService, ContentTypeService>();
|
||||
composition.RegisterUnique<IMediaTypeService, MediaTypeService>();
|
||||
composition.RegisterUnique<IDataTypeService, DataTypeService>();
|
||||
composition.RegisterUnique<IFileService, FileService>();
|
||||
composition.RegisterUnique<ILocalizationService, LocalizationService>();
|
||||
composition.RegisterUnique<IPackagingService, PackagingService>();
|
||||
composition.RegisterUnique<IServerRegistrationService, ServerRegistrationService>();
|
||||
composition.RegisterUnique<IEntityService, EntityService>();
|
||||
composition.RegisterUnique<IRelationService, RelationService>();
|
||||
composition.RegisterUnique<IMacroService, MacroService>();
|
||||
composition.RegisterUnique<IMemberTypeService, MemberTypeService>();
|
||||
composition.RegisterUnique<IMemberGroupService, MemberGroupService>();
|
||||
composition.RegisterUnique<INotificationService, NotificationService>();
|
||||
composition.RegisterUnique<IExternalLoginService, ExternalLoginService>();
|
||||
composition.RegisterUnique<IRedirectUrlService, RedirectUrlService>();
|
||||
composition.RegisterUnique<IConsentService, ConsentService>();
|
||||
composition.Register<LocalizedTextServiceFileSources>(SourcesFactory);
|
||||
composition.RegisterUnique<ILocalizedTextService>(factory => new LocalizedTextService(
|
||||
factory.GetInstance<Lazy<LocalizedTextServiceFileSources>>(),
|
||||
factory.GetInstance<ILogger>()));
|
||||
|
||||
//TODO: These are replaced in the web project - we need to declare them so that
|
||||
// something is wired up, just not sure this is very nice but will work for now.
|
||||
composition.RegisterUnique<IApplicationTreeService, EmptyApplicationTreeService>();
|
||||
composition.RegisterUnique<ISectionService, EmptySectionService>();
|
||||
|
||||
return composition;
|
||||
}
|
||||
|
||||
private static LocalizedTextServiceFileSources SourcesFactory(IFactory container)
|
||||
{
|
||||
var mainLangFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Umbraco + "/config/lang/"));
|
||||
var appPlugins = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins));
|
||||
var configLangFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Config + "/lang/"));
|
||||
|
||||
var pluginLangFolders = appPlugins.Exists == false
|
||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||
: appPlugins.GetDirectories()
|
||||
.SelectMany(x => x.GetDirectories("Lang"))
|
||||
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
|
||||
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 5)
|
||||
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false));
|
||||
|
||||
//user defined langs that overwrite the default, these should not be used by plugin creators
|
||||
var userLangFolders = configLangFolder.Exists == false
|
||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||
: configLangFolder
|
||||
.GetFiles("*.user.xml", SearchOption.TopDirectoryOnly)
|
||||
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 10)
|
||||
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true));
|
||||
|
||||
return new LocalizedTextServiceFileSources(
|
||||
container.GetInstance<ILogger>(),
|
||||
container.GetInstance<CacheHelper>().RuntimeCache,
|
||||
mainLangFolder,
|
||||
pluginLangFolders.Concat(userLangFolders));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods to the <see cref="Composition"/> class.
|
||||
/// </summary>
|
||||
public static class CompositionExtensions
|
||||
{
|
||||
#region Essentials
|
||||
|
||||
/// <summary>
|
||||
/// Registers essential services.
|
||||
/// </summary>
|
||||
public static void RegisterEssentials(this Composition composition,
|
||||
ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger,
|
||||
IMainDom mainDom,
|
||||
CacheHelper appCaches,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
TypeLoader typeLoader,
|
||||
IRuntimeState state)
|
||||
{
|
||||
composition.RegisterUnique(logger);
|
||||
composition.RegisterUnique(profiler);
|
||||
composition.RegisterUnique(profilingLogger);
|
||||
composition.RegisterUnique(mainDom);
|
||||
composition.RegisterUnique(appCaches);
|
||||
composition.RegisterUnique(factory => factory.GetInstance<CacheHelper>().RuntimeCache);
|
||||
composition.RegisterUnique(databaseFactory);
|
||||
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoDatabaseFactory>().SqlContext);
|
||||
composition.RegisterUnique(typeLoader);
|
||||
composition.RegisterUnique(state);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unique
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service as its own implementation.
|
||||
/// </summary>
|
||||
public static void RegisterUnique<TService>(this Composition composition)
|
||||
=> composition.RegisterUnique(typeof(TService), typeof(TService));
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service with an implementation type.
|
||||
/// </summary>
|
||||
public static void RegisterUnique<TService, TImplementing>(this Composition composition)
|
||||
=> composition.RegisterUnique(typeof(TService), typeof(TImplementing));
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service with an implementing instance.
|
||||
/// </summary>
|
||||
public static void RegisterUnique<TService>(this Composition composition, TService instance)
|
||||
=> composition.RegisterUnique(typeof(TService), instance);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using LightInject;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionRoots
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets up IoC container for Umbraco configuration classes
|
||||
/// </summary>
|
||||
public sealed class ConfigurationCompositionRoot : ICompositionRoot
|
||||
{
|
||||
public void Compose(IServiceRegistry container)
|
||||
{
|
||||
container.Register(factory => UmbracoConfig.For.UmbracoSettings());
|
||||
container.Register(factory => factory.GetInstance<IUmbracoSettingsSection>().Content);
|
||||
container.Register(factory => factory.GetInstance<IUmbracoSettingsSection>().Templates);
|
||||
container.Register(factory => factory.GetInstance<IUmbracoSettingsSection>().RequestHandler);
|
||||
container.Register(factory => UmbracoConfig.For.GlobalSettings());
|
||||
|
||||
// fixme - other sections we need to add?
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using LightInject;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionRoots
|
||||
{
|
||||
public sealed class CoreMappingProfilesCompositionRoot : ICompositionRoot
|
||||
{
|
||||
public void Compose(IServiceRegistry container)
|
||||
{
|
||||
container.Register<IdentityMapperProfile>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionRoots
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the IoC container for the umbraco data layer/repositories/sql/database/etc...
|
||||
/// </summary>
|
||||
public sealed class RepositoryCompositionRoot : ICompositionRoot
|
||||
{
|
||||
public const string DisabledCache = "DisabledCache";
|
||||
|
||||
public void Compose(IServiceRegistry container)
|
||||
{
|
||||
// register cache helpers
|
||||
// the main cache helper is registered by CoreBootManager and is used by most repositories
|
||||
// the disabled one is used by those repositories that have an annotated ctor parameter
|
||||
container.RegisterSingleton(factory => CacheHelper.CreateDisabledCacheHelper(), DisabledCache);
|
||||
|
||||
// resolve ctor dependency from GetInstance() runtimeArguments, if possible - 'factory' is
|
||||
// the container, 'info' describes the ctor argument, and 'args' contains the args that
|
||||
// were passed to GetInstance() - use first arg if it is the right type,
|
||||
//
|
||||
// for ...
|
||||
//container.RegisterConstructorDependency((factory, info, args) =>
|
||||
//{
|
||||
// if (info.Member.DeclaringType != typeof(EntityContainerRepository)) return default;
|
||||
// return args.Length > 0 && args[0] is Guid guid ? guid : default;
|
||||
//});
|
||||
|
||||
// register repositories
|
||||
// repos depend on various things,
|
||||
// some repositories have an annotated ctor parameter to pick the right cache helper
|
||||
|
||||
// repositories
|
||||
container.RegisterSingleton<IAuditRepository, AuditRepository>();
|
||||
container.RegisterSingleton<IAuditEntryRepository, AuditEntryRepository>();
|
||||
container.RegisterSingleton<IContentTypeRepository, ContentTypeRepository>();
|
||||
container.RegisterSingleton<IDataTypeContainerRepository, DataTypeContainerRepository>();
|
||||
container.RegisterSingleton<IDataTypeRepository, DataTypeRepository>();
|
||||
container.RegisterSingleton<IDictionaryRepository, DictionaryRepository>();
|
||||
container.RegisterSingleton<IDocumentBlueprintRepository, DocumentBlueprintRepository>();
|
||||
container.RegisterSingleton<IDocumentRepository, DocumentRepository>();
|
||||
container.RegisterSingleton<IDocumentTypeContainerRepository, DocumentTypeContainerRepository>();
|
||||
container.RegisterSingleton<IDomainRepository, DomainRepository>();
|
||||
container.RegisterSingleton<IEntityRepository, EntityRepository>();
|
||||
container.RegisterSingleton<IExternalLoginRepository, ExternalLoginRepository>();
|
||||
container.RegisterSingleton<ILanguageRepository, LanguageRepository>();
|
||||
container.RegisterSingleton<IMacroRepository, MacroRepository>();
|
||||
container.RegisterSingleton<IMediaRepository, MediaRepository>();
|
||||
container.RegisterSingleton<IMediaTypeContainerRepository, MediaTypeContainerRepository>();
|
||||
container.RegisterSingleton<IMediaTypeRepository, MediaTypeRepository>();
|
||||
container.RegisterSingleton<IMemberGroupRepository, MemberGroupRepository>();
|
||||
container.RegisterSingleton<IMemberRepository, MemberRepository>();
|
||||
container.RegisterSingleton<IMemberTypeRepository, MemberTypeRepository>();
|
||||
container.RegisterSingleton<INotificationsRepository, NotificationsRepository>();
|
||||
container.RegisterSingleton<IPublicAccessRepository, PublicAccessRepository>();
|
||||
container.RegisterSingleton<IRedirectUrlRepository, RedirectUrlRepository>();
|
||||
container.RegisterSingleton<IRelationRepository, RelationRepository>();
|
||||
container.RegisterSingleton<IRelationTypeRepository, RelationTypeRepository>();
|
||||
container.RegisterSingleton<IServerRegistrationRepository, ServerRegistrationRepository>();
|
||||
container.RegisterSingleton<ITagRepository, TagRepository>();
|
||||
container.RegisterSingleton<ITaskRepository, TaskRepository>();
|
||||
container.RegisterSingleton<ITaskTypeRepository, TaskTypeRepository>();
|
||||
container.RegisterSingleton<ITemplateRepository, TemplateRepository>();
|
||||
container.RegisterSingleton<IUserGroupRepository, UserGroupRepository>();
|
||||
container.RegisterSingleton<IUserRepository, UserRepository>();
|
||||
container.RegisterSingleton<IConsentRepository, ConsentRepository>();
|
||||
|
||||
// repositories that depend on a filesystem
|
||||
// these have an annotated ctor parameter to pick the right file system
|
||||
container.RegisterSingleton<IPartialViewMacroRepository, PartialViewMacroRepository>();
|
||||
container.RegisterSingleton<IPartialViewRepository, PartialViewRepository>();
|
||||
container.RegisterSingleton<IScriptRepository, ScriptRepository>();
|
||||
container.RegisterSingleton<IStylesheetRepository, StylesheetRepository>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Core.Composing.CompositionRoots
|
||||
{
|
||||
public sealed class ServicesCompositionRoot : ICompositionRoot
|
||||
{
|
||||
public void Compose(IServiceRegistry container)
|
||||
{
|
||||
// register a transient messages factory, which will be replaced by the web
|
||||
// boot manager when running in a web context
|
||||
container.RegisterSingleton<IEventMessagesFactory, TransientEventMessagesFactory>();
|
||||
|
||||
// register the service context
|
||||
container.RegisterSingleton<ServiceContext>();
|
||||
|
||||
// register the special idk map
|
||||
container.RegisterSingleton<IdkMap>();
|
||||
|
||||
// register the services
|
||||
container.RegisterSingleton<IKeyValueService, KeyValueService>();
|
||||
container.RegisterSingleton<IPublicAccessService, PublicAccessService>();
|
||||
container.RegisterSingleton<ITaskService, TaskService>();
|
||||
container.RegisterSingleton<IDomainService, DomainService>();
|
||||
container.RegisterSingleton<IAuditService, AuditService>();
|
||||
container.RegisterSingleton<ITagService, TagService>();
|
||||
container.RegisterSingleton<IContentService, ContentService>();
|
||||
container.RegisterSingleton<IUserService, UserService>();
|
||||
container.RegisterSingleton<IMemberService, MemberService>();
|
||||
container.RegisterSingleton<IMediaService, MediaService>();
|
||||
container.RegisterSingleton<IContentTypeService, ContentTypeService>();
|
||||
container.RegisterSingleton<IMediaTypeService, MediaTypeService>();
|
||||
container.RegisterSingleton<IDataTypeService, DataTypeService>();
|
||||
container.RegisterSingleton<IFileService, FileService>();
|
||||
container.RegisterSingleton<ILocalizationService, LocalizationService>();
|
||||
container.RegisterSingleton<IPackagingService, PackagingService>();
|
||||
container.RegisterSingleton<IServerRegistrationService, ServerRegistrationService>();
|
||||
container.RegisterSingleton<IEntityService, EntityService>();
|
||||
container.RegisterSingleton<IRelationService, RelationService>();
|
||||
container.RegisterSingleton<IMacroService, MacroService>();
|
||||
container.RegisterSingleton<IMemberTypeService, MemberTypeService>();
|
||||
container.RegisterSingleton<IMemberGroupService, MemberGroupService>();
|
||||
container.RegisterSingleton<INotificationService, NotificationService>();
|
||||
container.RegisterSingleton<IExternalLoginService, ExternalLoginService>();
|
||||
container.RegisterSingleton<IRedirectUrlService, RedirectUrlService>();
|
||||
container.RegisterSingleton<IConsentService, ConsentService>();
|
||||
container.Register<LocalizedTextServiceFileSources>(factory =>
|
||||
{
|
||||
var mainLangFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Umbraco + "/config/lang/"));
|
||||
var appPlugins = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins));
|
||||
var configLangFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Config + "/lang/"));
|
||||
|
||||
var pluginLangFolders = appPlugins.Exists == false
|
||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||
: appPlugins.GetDirectories()
|
||||
.SelectMany(x => x.GetDirectories("Lang"))
|
||||
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
|
||||
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 5)
|
||||
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false));
|
||||
|
||||
//user defined langs that overwrite the default, these should not be used by plugin creators
|
||||
var userLangFolders = configLangFolder.Exists == false
|
||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||
: configLangFolder
|
||||
.GetFiles("*.user.xml", SearchOption.TopDirectoryOnly)
|
||||
.Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 10)
|
||||
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true));
|
||||
|
||||
return new LocalizedTextServiceFileSources(
|
||||
factory.GetInstance<ILogger>(),
|
||||
factory.GetInstance<CacheHelper>().RuntimeCache,
|
||||
mainLangFolder,
|
||||
pluginLangFolders.Concat(userLangFolders));
|
||||
});
|
||||
container.RegisterSingleton<ILocalizedTextService>(factory => new LocalizedTextService(
|
||||
factory.GetInstance<Lazy<LocalizedTextServiceFileSources>>(),
|
||||
factory.GetInstance<ILogger>()));
|
||||
|
||||
//TODO: These are replaced in the web project - we need to declare them so that
|
||||
// something is wired up, just not sure this is very nice but will work for now.
|
||||
container.RegisterSingleton<IApplicationTreeService, EmptyApplicationTreeService>();
|
||||
container.RegisterSingleton<ISectionService, EmptySectionService>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
@@ -19,61 +20,46 @@ namespace Umbraco.Core.Composing
|
||||
/// Provides a static service locator for most singletons.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This class is initialized with the container in UmbracoApplicationBase,
|
||||
/// <para>This class is initialized with the container via LightInjectExtensions.ConfigureUmbracoCore,
|
||||
/// right after the container is created in UmbracoApplicationBase.HandleApplicationStart.</para>
|
||||
/// <para>Obviously, this is a service locator, which some may consider an anti-pattern. And yet,
|
||||
/// practically, it works.</para>
|
||||
/// </remarks>
|
||||
public static class Current
|
||||
{
|
||||
private static IFactory _factory;
|
||||
|
||||
// fixme - refactor
|
||||
// we don't want Umbraco tests to die because the container has not been properly initialized,
|
||||
// for some too-important things such as IShortStringHelper or loggers, so if it's not
|
||||
// registered we setup a default one. We should really refactor our tests so that it does
|
||||
// not happen.
|
||||
private static IServiceContainer _container;
|
||||
|
||||
private static IShortStringHelper _shortStringHelper;
|
||||
private static ILogger _logger;
|
||||
private static IProfiler _profiler;
|
||||
private static IProfilingLogger _profilingLogger;
|
||||
private static ProfilingLogger _profilingLogger;
|
||||
private static IPublishedValueFallback _publishedValueFallback;
|
||||
private static Configs _configs;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the factory.
|
||||
/// Gets or sets the DI container.
|
||||
/// </summary>
|
||||
public static IFactory Factory
|
||||
internal static IServiceContainer Container
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_factory == null) throw new InvalidOperationException("No factory has been set.");
|
||||
return _factory;
|
||||
if (_container == null) throw new Exception("No container has been set.");
|
||||
return _container;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_factory != null) throw new InvalidOperationException("A factory has already been set.");
|
||||
if (_configs != null) throw new InvalidOperationException("Configs are unlocked.");
|
||||
_factory = value;
|
||||
if (_container != null) throw new Exception("A container has already been set.");
|
||||
_container = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool HasFactory => _factory != null;
|
||||
internal static bool HasContainer => _container != null;
|
||||
|
||||
/// <summary>
|
||||
/// Resets <see cref="Current"/>. Indented for testing only, and not supported in production code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>For UNIT TESTS exclusively.</para>
|
||||
/// <para>Resets everything that is 'current'.</para>
|
||||
/// </remarks>
|
||||
public static void Reset()
|
||||
// for UNIT TESTS exclusively!
|
||||
// resets *everything* that is 'current'
|
||||
internal static void Reset()
|
||||
{
|
||||
_factory.DisposeIfDisposable();
|
||||
_factory = null;
|
||||
_container = null;
|
||||
|
||||
_configs = null;
|
||||
_shortStringHelper = null;
|
||||
_logger = null;
|
||||
_profiler = null;
|
||||
@@ -83,119 +69,94 @@ namespace Umbraco.Core.Composing
|
||||
Resetted?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unlocks <see cref="Configs"/>. Intended for testing only, and not supported in production code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>For UNIT TESTS exclusively.</para>
|
||||
/// <para>Unlocks <see cref="Configs"/> so that it is possible to add configurations
|
||||
/// directly to <see cref="Current"/> without having to wire composition.</para>
|
||||
/// </remarks>
|
||||
public static void UnlockConfigs()
|
||||
{
|
||||
if (_factory != null)
|
||||
throw new InvalidOperationException("Cannot unlock configs when a factory has been set.");
|
||||
_configs = new Configs();
|
||||
}
|
||||
|
||||
internal static event EventHandler Resetted;
|
||||
|
||||
#region Getters
|
||||
|
||||
// fixme - refactor
|
||||
// we don't want Umbraco to die because the container has not been properly initialized,
|
||||
// for some too-important things such as IShortStringHelper or loggers, so if it's not
|
||||
// registered we setup a default one. We should really refactor our tests so that it does
|
||||
// not happen. Will do when we get rid of IShortStringHelper.
|
||||
|
||||
public static IShortStringHelper ShortStringHelper
|
||||
=> _shortStringHelper ?? (_shortStringHelper = _factory?.TryGetInstance<IShortStringHelper>()
|
||||
?? new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(Configs.Settings())));
|
||||
=> _shortStringHelper ?? (_shortStringHelper = _container?.TryGetInstance<IShortStringHelper>()
|
||||
?? new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(UmbracoConfig.For.UmbracoSettings())));
|
||||
|
||||
public static ILogger Logger
|
||||
=> _logger ?? (_logger = _factory?.TryGetInstance<ILogger>()
|
||||
?? new DebugDiagnosticsLogger());
|
||||
=> _logger ?? (_logger = _container?.TryGetInstance<ILogger>()
|
||||
?? new DebugDiagnosticsLogger());
|
||||
|
||||
public static IProfiler Profiler
|
||||
=> _profiler ?? (_profiler = _factory?.TryGetInstance<IProfiler>()
|
||||
?? new LogProfiler(Logger));
|
||||
=> _profiler ?? (_profiler = _container?.TryGetInstance<IProfiler>()
|
||||
?? new LogProfiler(Logger));
|
||||
|
||||
public static IProfilingLogger ProfilingLogger
|
||||
=> _profilingLogger ?? (_profilingLogger = _factory?.TryGetInstance<IProfilingLogger>())
|
||||
public static ProfilingLogger ProfilingLogger
|
||||
=> _profilingLogger ?? (_profilingLogger = _container?.TryGetInstance<ProfilingLogger>())
|
||||
?? new ProfilingLogger(Logger, Profiler);
|
||||
|
||||
public static IRuntimeState RuntimeState
|
||||
=> Factory.GetInstance<IRuntimeState>();
|
||||
=> Container.GetInstance<IRuntimeState>();
|
||||
|
||||
public static TypeLoader TypeLoader
|
||||
=> Factory.GetInstance<TypeLoader>();
|
||||
=> Container.GetInstance<TypeLoader>();
|
||||
|
||||
public static Configs Configs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_configs != null) return _configs;
|
||||
if (_factory == null) throw new InvalidOperationException("Can not get Current.Config during composition. Use composition.Config.");
|
||||
return _factory.GetInstance<Configs>();
|
||||
}
|
||||
}
|
||||
|
||||
public static IFileSystems FileSystems
|
||||
=> Factory.GetInstance<IFileSystems>();
|
||||
|
||||
public static IMediaFileSystem MediaFileSystem
|
||||
=> Factory.GetInstance<IMediaFileSystem>();
|
||||
public static FileSystems FileSystems
|
||||
=> Container.GetInstance<FileSystems>();
|
||||
|
||||
public static UrlSegmentProviderCollection UrlSegmentProviders
|
||||
=> Factory.GetInstance<UrlSegmentProviderCollection>();
|
||||
=> Container.GetInstance<UrlSegmentProviderCollection>();
|
||||
|
||||
public static CacheRefresherCollection CacheRefreshers
|
||||
=> Factory.GetInstance<CacheRefresherCollection>();
|
||||
=> Container.GetInstance<CacheRefresherCollection>();
|
||||
|
||||
public static DataEditorCollection DataEditors
|
||||
=> Factory.GetInstance<DataEditorCollection>();
|
||||
=> Container.GetInstance<DataEditorCollection>();
|
||||
|
||||
public static PropertyEditorCollection PropertyEditors
|
||||
=> Factory.GetInstance<PropertyEditorCollection>();
|
||||
=> Container.GetInstance<PropertyEditorCollection>();
|
||||
|
||||
public static ParameterEditorCollection ParameterEditors
|
||||
=> Factory.GetInstance<ParameterEditorCollection>();
|
||||
=> Container.GetInstance<ParameterEditorCollection>();
|
||||
|
||||
internal static ManifestValueValidatorCollection ManifestValidators
|
||||
=> Factory.GetInstance<ManifestValueValidatorCollection>();
|
||||
=> Container.GetInstance<ManifestValueValidatorCollection>();
|
||||
|
||||
internal static PackageActionCollection PackageActions
|
||||
=> Factory.GetInstance<PackageActionCollection>();
|
||||
=> Container.GetInstance<PackageActionCollection>();
|
||||
|
||||
internal static PropertyValueConverterCollection PropertyValueConverters
|
||||
=> Factory.GetInstance<PropertyValueConverterCollection>();
|
||||
=> Container.GetInstance<PropertyValueConverterCollection>();
|
||||
|
||||
internal static IPublishedModelFactory PublishedModelFactory
|
||||
=> Factory.GetInstance<IPublishedModelFactory>();
|
||||
=> Container.GetInstance<IPublishedModelFactory>();
|
||||
|
||||
public static IServerMessenger ServerMessenger
|
||||
=> Factory.GetInstance<IServerMessenger>();
|
||||
=> Container.GetInstance<IServerMessenger>();
|
||||
|
||||
public static IServerRegistrar ServerRegistrar
|
||||
=> Factory.GetInstance<IServerRegistrar>();
|
||||
=> Container.GetInstance<IServerRegistrar>();
|
||||
|
||||
public static ICultureDictionaryFactory CultureDictionaryFactory
|
||||
=> Factory.GetInstance<ICultureDictionaryFactory>();
|
||||
=> Container.GetInstance<ICultureDictionaryFactory>();
|
||||
|
||||
public static CacheHelper ApplicationCache
|
||||
=> Factory.GetInstance<CacheHelper>();
|
||||
=> Container.GetInstance<CacheHelper>();
|
||||
|
||||
public static ServiceContext Services
|
||||
=> Factory.GetInstance<ServiceContext>();
|
||||
=> Container.GetInstance<ServiceContext>();
|
||||
|
||||
public static IScopeProvider ScopeProvider
|
||||
=> Factory.GetInstance<IScopeProvider>();
|
||||
=> Container.GetInstance<IScopeProvider>();
|
||||
|
||||
public static ISqlContext SqlContext
|
||||
=> Factory.GetInstance<ISqlContext>();
|
||||
=> Container.GetInstance<ISqlContext>();
|
||||
|
||||
public static IPublishedContentTypeFactory PublishedContentTypeFactory
|
||||
=> Factory.GetInstance<IPublishedContentTypeFactory>();
|
||||
=> Container.GetInstance<IPublishedContentTypeFactory>();
|
||||
|
||||
public static IPublishedValueFallback PublishedValueFallback
|
||||
=> _publishedValueFallback ?? Factory.GetInstance<IPublishedValueFallback>() ?? new NoopPublishedValueFallback();
|
||||
|
||||
public static IVariationContextAccessor VariationContextAccessor
|
||||
=> Factory.GetInstance<IVariationContextAccessor>();
|
||||
=> _publishedValueFallback ?? Container.GetInstance<IPublishedValueFallback>() ?? new NoopPublishedValueFallback();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods to the <see cref="IFactory"/> class.
|
||||
/// </summary>
|
||||
public static class FactoryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an instance of a service.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="factory">The factory.</param>
|
||||
/// <returns>An instance of the specified type.</returns>
|
||||
/// <remarks>Throws an exception if the factory failed to get an instance of the specified type.</remarks>
|
||||
public static T GetInstance<T>(this IFactory factory)
|
||||
=> (T)factory.GetInstance(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get an instance of a service.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <returns>An instance of the specified type, or null.</returns>
|
||||
/// <remarks>Returns null if the factory does not know how to get an instance
|
||||
/// of the specified type. Throws an exception if the factory does know how
|
||||
/// to get an instance of the specified type, but failed to do so.</remarks>
|
||||
public static T TryGetInstance<T>(this IFactory factory)
|
||||
=> (T)factory.TryGetInstance(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance with arguments.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the instance.</typeparam>
|
||||
/// <param name="factory">The factory.</param>
|
||||
/// <param name="args">Arguments.</param>
|
||||
/// <returns>An instance of the specified type.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Throws an exception if the factory failed to get an instance of the specified type.</para>
|
||||
/// <para>The arguments are used as dependencies by the factory.</para>
|
||||
/// </remarks>
|
||||
public static T CreateInstance<T>(this IFactory factory, params object[] args)
|
||||
=> (T)factory.CreateInstance(typeof(T), args);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of a service, with arguments.
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="type">The type of the instance.</param>
|
||||
/// <param name="args">Named arguments.</param>
|
||||
/// <returns>An instance of the specified type.</returns>
|
||||
/// <remarks>
|
||||
/// <para>The instance type does not need to be registered into the factory.</para>
|
||||
/// <para>The arguments are used as dependencies by the factory. Other dependencies
|
||||
/// are retrieved from the factory.</para>
|
||||
/// </remarks>
|
||||
public static object CreateInstance(this IFactory factory, Type type, params object[] args)
|
||||
{
|
||||
// LightInject has this, but then it requires RegisterConstructorDependency etc and has various oddities
|
||||
// including the most annoying one, which is that it does not work on singletons (hard to fix)
|
||||
//return factory.GetInstance(type, args);
|
||||
|
||||
// this method is essentially used to build singleton instances, so it is assumed that it would be
|
||||
// more expensive to build and cache a dynamic method ctor than to simply invoke the ctor, as we do
|
||||
// here - this can be discussed
|
||||
|
||||
// TODO: we currently try the ctor with most parameters, but we could want to fall back to others
|
||||
|
||||
var ctor = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public).OrderByDescending(x => x.GetParameters().Length).FirstOrDefault();
|
||||
if (ctor == null) throw new InvalidOperationException($"Could not find a public constructor for type {type.FullName}.");
|
||||
|
||||
var ctorParameters = ctor.GetParameters();
|
||||
var ctorArgs = new object[ctorParameters.Length];
|
||||
var i = 0;
|
||||
foreach (var parameter in ctorParameters)
|
||||
{
|
||||
// no! IsInstanceOfType is not ok here
|
||||
// ReSharper disable once UseMethodIsInstanceOfType
|
||||
var arg = args?.FirstOrDefault(a => parameter.ParameterType.IsAssignableFrom(a.GetType()));
|
||||
ctorArgs[i++] = arg ?? factory.GetInstance(parameter.ParameterType);
|
||||
}
|
||||
return ctor.Invoke(ctorArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,11 @@
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a collection builder.
|
||||
/// </summary>
|
||||
public interface ICollectionBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the builder so it can build the collection, by
|
||||
/// registering the collection and the types.
|
||||
/// </summary>
|
||||
void RegisterWith(IRegister register);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a collection builder.
|
||||
/// </summary>
|
||||
/// <typeparam name="TCollection">The type of the collection.</typeparam>
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public interface ICollectionBuilder<out TCollection, TItem> : ICollectionBuilder
|
||||
public interface ICollectionBuilder<out TCollection, TItem>
|
||||
where TCollection : IBuilderCollection<TItem>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -25,6 +13,6 @@
|
||||
/// </summary>
|
||||
/// <returns>A collection.</returns>
|
||||
/// <remarks>Creates a new collection each time it is invoked.</remarks>
|
||||
TCollection CreateCollection(IFactory factory);
|
||||
TCollection CreateCollection();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
// Implementing:
|
||||
//
|
||||
// The factory
|
||||
// - always picks the constructor with the most parameters
|
||||
// - supports Lazy parameters (and prefers them over non-Lazy) in constructors
|
||||
// - what happens with 'releasing' is unclear
|
||||
|
||||
/// <summary>
|
||||
/// Defines a service factory for Umbraco.
|
||||
/// </summary>
|
||||
public interface IFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the concrete factory.
|
||||
/// </summary>
|
||||
object Concrete { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of a service.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the service.</param>
|
||||
/// <returns>An instance of the specified type.</returns>
|
||||
/// <remarks>Throws an exception if the container failed to get an instance of the specified type.</remarks>
|
||||
object GetInstance(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get an instance of a service.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the service.</param>
|
||||
/// <returns>An instance of the specified type, or null.</returns>
|
||||
/// <remarks>Returns null if the container does not know how to get an instance
|
||||
/// of the specified type. Throws an exception if the container does know how
|
||||
/// to get an instance of the specified type, but failed to do so.</remarks>
|
||||
object TryGetInstance(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all instances of a service.
|
||||
/// </summary>
|
||||
/// <param name="serviceType">The type of the service.</param>
|
||||
IEnumerable<object> GetAllInstances(Type serviceType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all instances of a service.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">The type of the service.</typeparam>
|
||||
IEnumerable<TService> GetAllInstances<TService>();
|
||||
|
||||
/// <summary>
|
||||
/// Releases an instance.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance.</param>
|
||||
/// <remarks>
|
||||
/// See https://stackoverflow.com/questions/14072208 and http://kozmic.net/2010/08/27/must-i-release-everything-when-using-windsor/,
|
||||
/// you only need to release instances you specifically resolved, and even then, if done right, that might never be needed. For
|
||||
/// instance, LightInject does not require this and does not support it - should work with scopes.
|
||||
/// </remarks>
|
||||
void Release(object instance);
|
||||
|
||||
/// <summary>
|
||||
/// Begins a scope.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>When the scope is disposed, scoped instances that have been created during the scope are disposed.</para>
|
||||
/// <para>Scopes can be nested. Each instance is disposed individually.</para>
|
||||
/// </remarks>
|
||||
IDisposable BeginScope();
|
||||
|
||||
/// <summary>
|
||||
/// Enables per-request scope.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Ties scopes to web requests.</para>
|
||||
/// </remarks>
|
||||
void EnablePerWebRequestScope();
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
// Implementing:
|
||||
//
|
||||
// The register
|
||||
// - supports registering a service, even after some instances of other services have been created
|
||||
// - supports re-registering a service, as long as no instance of that service has been created
|
||||
// - throws when re-registering a service, and an instance of that service has been created
|
||||
//
|
||||
// - registers only one implementation of a nameless service, re-registering replaces the previous
|
||||
// registration - names are required to register multiple implementations - and getting an
|
||||
// IEnumerable of the service, nameless, returns them all
|
||||
|
||||
/// <summary>
|
||||
/// Defines a service register for Umbraco.
|
||||
/// </summary>
|
||||
public interface IRegister
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the concrete container.
|
||||
/// </summary>
|
||||
object Concrete { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service as its own implementation.
|
||||
/// </summary>
|
||||
void Register(Type serviceType, Lifetime lifetime = Lifetime.Transient);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service with an implementation type.
|
||||
/// </summary>
|
||||
void Register(Type serviceType, Type implementingType, Lifetime lifetime = Lifetime.Transient);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service with an implementation factory.
|
||||
/// </summary>
|
||||
void Register<TService>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service with an implementing instance.
|
||||
/// </summary>
|
||||
void RegisterInstance(Type serviceType, object instance);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a base type for auto-registration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Auto-registration means that anytime the container is asked to create an instance
|
||||
/// of a type deriving from <paramref name="serviceBaseType"/>, it will first register that
|
||||
/// type automatically.</para>
|
||||
/// <para>This can be used for instance for views or controllers. Then, one just needs to
|
||||
/// register a common base class or interface, and the container knows how to create instances.</para>
|
||||
/// </remarks>
|
||||
void RegisterAuto(Type serviceBaseType);
|
||||
|
||||
#region Control
|
||||
|
||||
/// <summary>
|
||||
/// Configures the container for web support.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Enables support for MVC, WebAPI, but *not* per-request scope. This is used early in the boot
|
||||
/// process, where anything "scoped" should not be linked to a web request.</para>
|
||||
/// </remarks>
|
||||
void ConfigureForWeb();
|
||||
|
||||
/// <summary>
|
||||
/// Creates the factory.
|
||||
/// </summary>
|
||||
IFactory CreateFactory();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
@@ -14,22 +15,31 @@ namespace Umbraco.Core.Composing
|
||||
where TBuilder : LazyCollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TCollection : IBuilderCollection<TItem>
|
||||
{
|
||||
private readonly List<Func<IEnumerable<Type>>> _producers = new List<Func<IEnumerable<Type>>>();
|
||||
private readonly List<Func<IEnumerable<Type>>> _producers1 = new List<Func<IEnumerable<Type>>>();
|
||||
private readonly List<Func<IServiceFactory, IEnumerable<Type>>> _producers2 = new List<Func<IServiceFactory, IEnumerable<Type>>>();
|
||||
private readonly List<Type> _excluded = new List<Type>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LazyCollectionBuilderBase{TBuilder,TCollection,TItem}"/> class.
|
||||
/// </summary>
|
||||
protected LazyCollectionBuilderBase(IServiceContainer container)
|
||||
: base(container)
|
||||
{ }
|
||||
|
||||
protected abstract TBuilder This { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Clears all types in the collection.
|
||||
/// </summary>
|
||||
/// <returns>The builder.</returns>
|
||||
/// <returns>The buidler.</returns>
|
||||
public TBuilder Clear()
|
||||
{
|
||||
Configure(types =>
|
||||
{
|
||||
types.Clear();
|
||||
_producers.Clear();
|
||||
_excluded.Clear();
|
||||
_producers1.Clear();
|
||||
_producers2.Clear();
|
||||
_excluded.Clear();
|
||||
});
|
||||
return This;
|
||||
}
|
||||
@@ -65,6 +75,37 @@ namespace Umbraco.Core.Composing
|
||||
return This;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a type from the collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to remove.</typeparam>
|
||||
/// <returns>The builder.</returns>
|
||||
public TBuilder Remove<T>()
|
||||
where T : TItem
|
||||
{
|
||||
Configure(types =>
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (types.Contains(type)) types.Remove(type);
|
||||
});
|
||||
return This;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a type from the collection.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to remove.</param>
|
||||
/// <returns>The builder.</returns>
|
||||
public TBuilder Remove(Type type)
|
||||
{
|
||||
Configure(types =>
|
||||
{
|
||||
EnsureType(type, "remove");
|
||||
if (types.Contains(type)) types.Remove(type);
|
||||
});
|
||||
return This;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a types producer to the collection.
|
||||
/// </summary>
|
||||
@@ -74,7 +115,21 @@ namespace Umbraco.Core.Composing
|
||||
{
|
||||
Configure(types =>
|
||||
{
|
||||
_producers.Add(producer);
|
||||
_producers1.Add(producer);
|
||||
});
|
||||
return This;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a types producer to the collection.
|
||||
/// </summary>
|
||||
/// <param name="producer">The types producer.</param>
|
||||
/// <returns>The builder.</returns>
|
||||
public TBuilder Add(Func<IServiceFactory, IEnumerable<Type>> producer)
|
||||
{
|
||||
Configure(types =>
|
||||
{
|
||||
_producers2.Add(producer);
|
||||
});
|
||||
return This;
|
||||
}
|
||||
@@ -113,7 +168,8 @@ namespace Umbraco.Core.Composing
|
||||
protected override IEnumerable<Type> GetRegisteringTypes(IEnumerable<Type> types)
|
||||
{
|
||||
return types
|
||||
.Union(_producers.SelectMany(x => x()))
|
||||
.Union(_producers1.SelectMany(x => x()))
|
||||
.Union(_producers2.SelectMany(x => x(Container)))
|
||||
.Distinct()
|
||||
.Select(x => EnsureType(x, "register"))
|
||||
.Except(_excluded);
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the lifetime of a registered instance.
|
||||
/// </summary>
|
||||
public enum Lifetime
|
||||
{
|
||||
/// <summary>
|
||||
/// Always get a new instance.
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to Transient in LightInject, Castle Windsor
|
||||
/// or MS.DI, PerDependency in Autofac.</remarks>
|
||||
Transient,
|
||||
|
||||
/// <summary>
|
||||
/// One unique instance per request.
|
||||
/// </summary>
|
||||
// fixme - not what you think!
|
||||
// currently, corresponds to 'Request' in LightInject which is 'Transient + disposed by Scope'
|
||||
// but NOT (in LightInject) a per-web-request lifetime, more a TransientScoped
|
||||
//
|
||||
// we use it for controllers, httpContextBase and umbracoContext
|
||||
// - so that they are automatically disposed at the end of the scope (ie request)
|
||||
// - not sure they should not be simply 'scoped'?
|
||||
//
|
||||
// Castle has an extra PerWebRequest something, and others use scope
|
||||
// what about Request before first request ie during application startup?
|
||||
// see http://blog.ploeh.dk/2009/11/17/UsingCastleWindsor'sPerWebRequestlifestylewithASP.NETMVConIIS7/
|
||||
// Castle ends up requiring a special scope manager too
|
||||
// see https://groups.google.com/forum/#!topic/castle-project-users/1E2W9LVIYR4
|
||||
//
|
||||
// but maybe also - why are we requiring scoped services at startup?
|
||||
Request,
|
||||
|
||||
/// <summary>
|
||||
/// One unique instance per container scope.
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to Scope in LightInject, Scoped in MS.DI
|
||||
/// or Castle Windsor, PerLifetimeScope in Autofac.</remarks>
|
||||
Scope,
|
||||
|
||||
/// <summary>
|
||||
/// One unique instance per container.
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to Singleton in LightInject, Castle Windsor
|
||||
/// or MS.DI and to SingleInstance in Autofac.</remarks>
|
||||
Singleton
|
||||
}
|
||||
}
|
||||