Upgrading to DotVVM 1.1
Because DotVVM 1.1 brought support for ASP.NET Core, we had to do many fundamental changes inside the framework, and there are several breaking changes.
If your app is built on DotVVM 1.0, you need to take the following steps to upgrade to DotVVM 1.1 on OWIN.
1. Install the DotVVM.Owin NuGet Package
In the 1.0 version, the DotVVM NuGet package included the framework and the hosting infrastructure together in one library.
In the 1.1 version, we have moved the OWIN hosting infrastructure to a separate package, and that's why you need to add it to your project.
2. Change OwinContext to GetOwinContext() or to HttpContext
The Context
object which is available in the viewmodel, had the OwinContext
property which could access the information about the current HTTP request
and manipulate with the response.
Because the API changed on ASP.NET Core, we have added the HttpContext
property which provides a unified API for OWIN and ASP.NET Core.
However, there are some differences and there are not all features available in the original OwinContext
property.
If you want to get the real OWIN context, you can call the GetOwinContext()
extension method and get the same API. The GetOwinContext()
method is
in the Dotvvm.Framework.Hosting
namespace.
3. Change OwinContext.Authentication to GetAuthentication()
The same thing applies to OwinContext.Authentication
property. You can use the GetAuthentication()
extension method to get this API quickly.
4. Change DotvvmRequestContext to IDotvvmRequestContext in Custom Presenters
In the 1.0 version, the IDotvvmRequestContext
declared the ProcessRequest
method with an argument of type DotvvmRequestContext
, which was wrong.
In the 1.1 version, we fixed this, so the argument is IDotvvmRequestContext
, which allows to mock the context easily when testing the presenter.
5. DefaultViewModelLoader requires IServiceProvider
If you derived from the DefaultViewModelLoader
class to do the dependency injection in the viewmodels, you need to request the IServiceProvider
argument
in the constructor of your class, and pass it to the constructor of DefaultViewModelLoader
.
public class WindsorViewModelLoader : DefaultViewModelLoader
{
private readonly WindsorContainer container;
public WindsorViewModelLoader(WindsorContainer container)
{
this.container = container;
}
...
}
6. ServiceLocator changes to IServiceProvider
Since Microsoft has brought their own dependency injection mechanisms in the ASP.NET Core, to make the things unified, we have used this infrastructure in DotVVM too.
If you registered custom services in the DotvvmConfiguration.ServiceLocator
, you have to change the registrations to the following ones:
var dotvvmConfiguration = app.UseDotVVM<DotvvmStartup>(applicationPhysicalPath, options: options =>
{
options.Services.AddSingleton<IViewModelLoader>(serviceProvider => new WindsorViewModelLoader(container));
});
You will need to import the Microsoft.Extensions.DependencyInjection
namespace to do so.
Also, you can only register services in the UseDotVVM
method by passing a method to the options
parameter.
If you try to add services in the IServiceProvider
later, it may fail because the object denies changes to its configuration after the first service is resolved.
7. Make ActionFilter and ExceptionFilter Methods Async
We needed to change all methods on the ActionFilterAttribute
and ExceptionFilterAttribute
to async versions.
protected override Task OnCommandExceptionAsync(IDotvvmRequestContext context, ActionInfo actionInfo, Exception exception)
{
...
}
Also, if you want to intercept only some of the methods, you don't need to derive from the ActionFilterAttribute
, but you can only implement one of the
following interfaces:
IPageActionFilter
contains page-level events -OnPageLoadingAsync
,OnPageLoadedAsync
andOnPageExceptionAsync
.ICommandActionFilter
contains command-related events -OnCommandExecutingAsync
andOnCommandExecutedAsync
.IViewModelActionFilter
contains viewmodel-related events -OnViewModelCreatedAsync
andOnViewModelDeserializedAsync
andOnViewModelSerializingAsync
(which replaces theOnResponseRendering
).
8. Rename the HideNonAuthenticatedUsers to HideForAnonymousUsers on RoleView
If you are using the <dot:RoleView>
control, please rename the HideNonAuthenticatedUsers
to HideForAnonymousUsers
property which makes better sense.
9. Resource Registrations Changed
To support advanced scenarios, we had to change the way how resources are registered.
The ScriptResource
and StylesheetResource
classes don't have the Url
property any more, they got the Location
property instead. Additionally, the Location
is not a string
, but it can be of the following classes:
UrlResourceLocation
specifies just the URL where the resource can be found. You can use either absolute URL (e.g. to point to some CDN), a relative URL to your server, or even a data URI. DotVVM will render the<script>
or<link>
element with the exact URL you have specified.LocalFileResourceLocation
expects the app-relative filesystem path to the script or stylesheet file. This path should not start with/
- it would point to the root of the filesystem. DotVVM will render the<script>
or<link>
element which points to a DotVVM resource handler (~/dotvvmResource/checksum/resourceName
) that will serve the resource. This is useful for bundling or advanced scenarios.EmbeddedResourceLocation
can extract the embedded resource from an assembly. This is very useful if you need to pack some DotVVM controls in a library and embed the resources in the DLL file.
Also, we have dropped the following properties from the ScriptResource
class:
CdnUrl
is replaced withLocationFallback
property and supports multiple fallback locations.EmbeddedResourceAssembly
property which switched the resource to the embedded resource mode, was replaced with theEmbeddedResourceLocation
object.GlobalObjectName
was moved toLocationFallback.JavascriptCondition
.
In basic scenarios, you just need to replace the Url
with Location
and wrap the string URL in the UrlResourceLocation
:
config.Resources.Register("bootstrap", new ScriptResource()
{
// Url = "~/Scripts/bootstrap.min.js",
Location =new UrlResourceLocation("~/Scripts/bootstrap.min.js"),
Dependencies = new[] { "bootstrap-css", "jquery" }
});
If you have used the embedded resources, you should use the following way of working with CdnUrl
, GlobalObjectName
and EmbeddedResourceAssembly
:
configuration.Resources.Register(ResourceConstants.JQueryResourceName,
new ScriptResource()
{
// CdnUrl = "https://code.jquery.com/jquery-2.1.1.min.js",
// Url = "DotVVM.Framework.Resources.Scripts.jquery-2.1.1.min.js",
// EmbeddedResourceAssembly = typeof (DotvvmConfiguration).Assembly.GetName().Name,
// GlobalObjectName = "window.jQuery"
Location = new UrlResourceLocation("https://code.jquery.com/jquery-2.1.1.min.js"))
{
LocationFallback = new ResourceLocationFallback(
"window.jQuery",
new EmbeddedResourceLocation(typeof(DotvvmConfiguration).GetTypeInfo().Assembly, "DotVVM.Framework.Resources.Scripts.jquery-2.1.1.min.js"))
}
});