Giter Club home page Giter Club logo

geta / geta-notfoundhandler Goto Github PK

View Code? Open in Web Editor NEW
19.0 14.0 15.0 85.18 MB

The popular NotFound handler for ASP.NET Core and Optimizely, enabling better control over your 404 page in addition to allowing redirects for old URLs that no longer works.

License: Apache License 2.0

PowerShell 0.01% C# 66.58% HTML 22.80% CSS 0.24% JavaScript 6.57% Batchfile 0.21% Shell 0.08% SCSS 3.48% ASP.NET 0.03%
aspnetcore cms commerce notfound optimizely 404error

geta-notfoundhandler's Introduction

NotFound Handler for ASP.NET Core and Optimizely

Build Quality Gate Status Platform Platform

Description

The popular NotFound handler for ASP.NET Core and Optimizely, enabling better control over your 404 page in addition to allowing redirects for old URLs that no longer works.

The perfect companion if you're transitioning to your site from another system and cannot keep the URL structure, or plan to do major re-structuring of your content.

Features

  • The NotFound handler stores the redirects in the database. Editors can add redirects without any deployments.
  • All redirects are edited in the Admin UI as shown above. After the add-on is installed and a proper 404 page has been created, no changes to the application is needed to add new redirects.
  • You can import and export redirects as XML from the Admin UI.
  • Handles partial and "full" URLs and can redirect out of the site by using fully qualified URLs for the "New url" field.
  • Supports wildcard redirects.
  • By using fully qualified URLs in the "Old url" field, they will only apply for that specific site. Editing redirects is done for all sites in the same UI.

Installation

The command below will install Admin UI and NotFound handler into your ASP.NET Core project.

Install-Package Geta.NotFoundHandler.Admin

If you need only the handler, then you can install it by the command below.

Install-Package Geta.NotFoundHandler

For the Optimizely project, you would want to install Admin UI integration package.

Install-Package Geta.NotFoundHandler.Optimizely

For the Optimizely Commerce project, if you want to use Automatic redirects, install:

Install-Package Geta.NotFoundHandler.Optimizely.Commerce

The package can be found in the Optimizely Nuget Feed.

Configuration

Add the NotFound handler in the Startup.cs in the ConfigureServices method. Below is an example with all available configuration you can set. For Optimizely project, also call AddOptimizelyNotFoundHandler - it will add Admin UI in the Optimizely admin UI.

public void ConfigureServices(IServiceCollection services)
{
    var connectionString = ... // Retrieve connection string here
    services.AddNotFoundHandler(o =>
    {
        o.UseSqlServer(connectionstring);
        o.BufferSize = 30;
        o.ThreshHold = 5;
        o.HandlerMode = FileNotFoundMode.On;
        o.IgnoredResourceExtensions = new[] { "jpg", "gif", "png", "css", "js", "ico", "swf", "woff" };
        o.Logging = LoggerMode.On;
        o.LogWithHostname = false;
        o.AddProvider<NullNotFoundHandlerProvider>();
    });

    services.AddOptimizelyNotFoundHandler(o =>
    {
        o.AutomaticRedirectsEnabled = true;
        o.AddOptimizelyCommerceProviders();
    });

...
}

The first and the mandatory configuration is a connection string. Use UseSqlServer method to set up the database connection string.

Call the AddOptimizelyNotFoundHandler method in Optimizely projects. To enable Automatic redirects, you should set AutomaticRedirectsEnabled to true and for Optimizely Commerce projects call AddOptimizelyCommerceProviders.

In addition, the configuration can be read from the appsettings.json:

"Geta": {
    "NotFoundHandler": {
        "BufferSize":  40
    }
}

The configuration from the appsettings.json will override any configuration set in the Startup. Note that you cannot provide a connection string or add providers in the appsetings.json. All other settings are supported.

Next, initialize NotFound handler in the Configure method as the first registration. It will make sure that NotFound handler will catch all 404 errors. For Optimizely project, also call UseOptimizelyNotFoundHandler. This will make sure that any updates are synchronized between servers (on DXP, for example).

public void Configure(IApplicationBuilder app)
{
    app.UseNotFoundHandler();
    app.UseOptimizelyNotFoundHandler();
...
}

Also, you have to add Razor pages routing support.

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

Settings

HandlerMode You can turn off the redirects by setting HandlerMode to Off. Default is On.

Logging

Suggestions for NotFound rules require 404 requests to be logged to the database.

Logging of 404 requests is buffered to shield your application from Denial of Service attacks. By default, logging will happen for every 30'th error. You can change this setting in the configuration and set bufferSize to 0 to log the errors immediately. This is not recommended as you will be vulnerable to massive logging to your database. You can control how much you would like to log by specifying a threshold value. This value determines how frequently 404 errors are allowed to be logged.

Important! Even if the threshold is set low, you can still receive a lot of requests in the 404 log. In the Admin view (follow "Administer" link in gadget) you can delete suggestions (logged 404 requests). You can find all the logged items in the NotFoundHandler.Suggestions table in your database if you want to manually clear the logged requests (this will not remove any redirects).

Logging: Turn logging On or Off. Default is On

BufferSize: Size of memory buffer to hold 404 requests. Default is 30

Threshold: Average maximum allowed requests per second. Default is 5

  • Example 1:
    • bufferSize is set to 100, threshold is set to 10
    • Case: 100 errors in 5 seconds - (diff = seconds between first logged request and the last logged request in the buffer).
    • 100 / 5 = 20. Error frequency is higher than threshold value. Buffered requests will not get logged, the entire buffer will be discarded.
  • Example 2:
    • bufferSize is 100, threshold is 10
    • Case: 100 errors in 15 seconds
    • 100 / 15 = 6. Error frequency is within threshold value. Buffered requests will get logged.

If the bufferSize is set to 0, the threshold value will be ignored, and every request will be logged immediately.

LogWithHostname: Set to true to include hostname in the log. Useful in a multisite environment with several hostnames/domains. Default is false

Specifying ignored resources

IgnoredResourceExtensions

By default, requests to files with the following extensions will be ignored by the redirect module: jpg,gif,png,css,js,ico,swf,woff

If you want to specify this yourself, add IgnoredResourceExtensions to the configuration.

Restricting access to the Admin UI

By default, only users of Administrators role can access Admin UI. But you can configure you authorization policy when registrating the NotFound handler.

 services.AddNotFoundHandler(o => { },
            policy =>
            {
                policy.RequireRole("MyRole");
            });

You can setup any policy rules you want.

Import

For details see Import redirects for 404 handler article.

Custom 404 Page

To setup 404 page, you can use any method ASP.NET Core provides.

One of the simplest solutions is adding a controller and a view for it that would display an error page:

[Route("error")]
public class ErrorController : Controller
{
    [Route("404")]
    public IActionResult PageNotFound()
    {
        return View();
    }
}

Then register status code pages in the Startup's Configure method before NotFound handler registration:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseStatusCodePagesWithReExecute("/error/{0}");
    app.UseNotFoundHandler();

...
}

Registering before the NotFound handler will make sure that a NotFound handler already checked the error and only those errors that were not handled by NotFound handler will be redirected to the error page.

Custom Handlers

If you need more advanced or custom logic to create redirects, you can implement an INotFoundHandler.

  1. Create a class that implements Geta.NotFoundHandler.Core
  2. In the public string RewriteUrl(string url) method, add your custom logic
  3. Register the handler in the configuration.
services.AddNotFoundHandler(o =>
{
        o.AddProvider<CustomProductRedirectHandler>();
});

This is especially useful for rewrites that follow some kind of logic, like checking the querystring for and id or some other value you can use to look up the page.

Here is an example using Optimizely Find to look up a product by code:

public class CustomProductRedirectHandler : INotFoundHandler
{
    public string RewriteUrl(string url)
    {
        if(url.Contains("productid"))
        {
            // Give it a thorough look - see if we can redirect it
            Url uri = new Url(url);
            var productId = uri.QueryCollection.GetValues("productid").FirstOrDefault();
            if (productId != null && string.IsNullOrEmpty(productId) == false)
            {
                SearchResults<FindProduct> results = SearchClient.Instance.Search<FindProduct>()
                    .Filter(p => p.Code.MatchCaseInsensitive(productId))
                    .GetResult();
                if (results.Hits.Any())
                {
                    // Pick the first one
                    SearchHit<FindProduct> product = results.Hits.FirstOrDefault();
                    return product.Document.ProductUrl;
                }
            }
        }
        return null;
    }
}

Note! Make sure the code you add has good performance, it could be called a lot. If you're querying a database or a search index, you might want to add caching and perhaps Denial Of Service prevention measures.

Automatic redirects

Automatic redirects is a feature that when enabled will create redirects for content that is moved.

See the Configuration section how to enable it.

Once you enabled Automatic redirects, you should run [Geta NotFoundHandler] Index content URLs scheduled job. It will index all URLs of content and will start monitoring those for changes.

Now Automatic redirects will create redirects on content move. It will create redirects with the old URLs by checking the indexed URLs for the content and new URLs of the new place where a content is moved to. After that, it will index new URLs too.

It will monitor primary, secondary and SEO URLs:

  • a primary URL will be redirected to the new primary URL,
  • all secondary URLs will be redirected to the new primary URL,
  • a SEO URL is redirected to the new SEO URL if possible and to the new primary URL, if not possible.

Optimizely Content Cloud supports only primary URLs and Optimizely Commerce supports all three types of URLs.

There are two scheduled jobs:

  • [Geta NotFoundHandler] Index content URLs - as mentioned before, this job indexes URLs of content. Usually, it is required to run this job only once. All new content is automatically indexed. But if for some reasons content publish events are not firing when creating new content (for example, during the import), then you should set this job to run frequently.
  • [Geta NotFoundHandler] Register content move redirects - this job creates redirects based on registered moved content. Normally, this job is not required at all, but there might be situations when content move is registered but redirect creation is not completed. This could happen during deployments. In this case, you can manually run this job or schedule it to run time to time to fix such issues.

Troubleshooting

The module has extensive logging. Turn on debug logging for the Geta.NotFoundHandler namespace in your logging configuration.

Usage

Wildcards

If you want to redirect many addresses below a specific one to one new URL, set this to true. If we get a wild card match on this URL, the new URL will be used in its raw format and the old URL will not be appended to the new one.

For example, if we have a redirect: /a to /b, then:

  • with wildcard setting it will redirect /a/1 to /b
  • without wildcard setting it will redirect /a/1 to /b/1

Sandbox App

Sandbox application is testing poligon for pacakge new features and bug fixes.

CMS username: [email protected]

Password: Episerver123!

Contributing

If you can help please do so by contributing to the package! Reach out package maintainer for additional details if needed.

Package Maintainer

https://github.com/marisks

geta-notfoundhandler's People

Contributors

ellinge avatar gergroot avatar jevgenijsp avatar kaspars-ozols avatar lk-luca avatar marisks avatar palle-mertz-isobar avatar pmertz avatar svenrog avatar valdisiljuconoks avatar yungis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

geta-notfoundhandler's Issues

Issue while updating an existing 301 redirect.

I observed that when I update an existing 301 redirect in NotFound handler in CMS 12, the server returns both old and new landing pages randomly after the update. We tested this in multiple machines using different tools. The new redirects will reflect only after couple of hours.

It seems like the updated redirection is not published to all server instances instantly resulting in inconsistent redirects. There was a comment from Optimizely support team that the NotFound plugin may not have implemented object cache correctly, causing the cached redirections to be different across load balanced instances. This issue is currently causing inconsistent redirects.

Bug: class RequestHandler function IsResourceFile extension resolving problem

Hello,

First thank you for this extension, we are using it and find it very useful.

While I was investigating a callstack exception in NotFoundHandler, I found a small bug in your code.

Where ?
class RequestHandler function IsResourceFile

How ?
If the url is for instance "https://localhost:44396/EPiServer/EPiServer.Cms.TinyMce/3.2.0/ClientResources/tinymce/langs/en-ca.js"
then the extension will be "Cms.TinyMce/3.2.0/ClientResources/tinymce/langs/en-ca.js" which will not be filtered out by the IgnoredResourceExtensions.
Thus if the url contains a dot in the path before the real extension the filtering will not work as intended.

It should be easy to fix on your side and an important fix, let me now if you need more help.

Thank you very much !

Unable to find a module

When i try to go into episerver ui i get the following error:

An unhandled exception has occurred while executing the request.
System.ArgumentException: Unable to find a module by assembly 'Geta.NotFoundHandler.Optimizely, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' (Parameter 'moduleAssembly')
at EPiServer.Shell.Paths.ToResource(Assembly moduleAssembly, String moduleRelativeResourcePath)
at EPiServer.Shell.Paths.ToResource(Type typeInModuleAssembly, String moduleRelativeResourcePath)
at Geta.NotFoundHandler.Optimizely.MenuProvider.GetMenuItems()

IIS Trying to load Admin Static Assets from Local Nuget folder

Hi,

When I run my site on my local machine in IIS, I get a 'DirectoryNotFoundException'.

image

Why is the site trying to serve assets from my local nuget folder? I can grant permissions to this directory and it loads... but this solution will not be possible when the site is later deployed into production.

Should I be able to move these static assets into my solution and specify the path somehow in config? Note, I've tried specifying the path via clientResourceRelativePath in the modules.config but it does not seem to respect the value I pace here.

Any help would be greatly appreciated

Thanks in advance
Dan

How disable NotFoundHandler on virtual paths?

Hi @marisks this looks good, so wanted to take NotFoundHandler on a testdrive.

BUT we are using https://github.com/ligershark/WebOptimizer for CSS and Javascript bundling.

We do register weboptimizer like this

services.AddWebOptimizer(pipeline => { pipeline.AddCssBundle("/css/bundle.css", "/**/*.css"); pipeline.AddJavaScriptBundle("/js/bundle.js", "js/**/*.js"); });

image

Seems when we installed NotFoundHandler this stopped to work, is the NotFoundHandler hijacking the pipeline somehow? When we remove the AddNotFoundHandler the css bundling is working, any idea?

Redirects created to recycle bin

We have an issue where pages sent to the recycle bin gets redirects created for them to the recycle bin. I had a sample page at the url /sv/testsida which I threw in the recycle bin and then a redirect was added to /sv/Recycle-Bin/testsida.

image

When I browse to the old url I get a 404 page as expected, but the user is first redirected to /sv/Recycle-Bin/testsida which looks really bad.

Is this expected behaviour? If so, is there any way for me to filter out these urls since we don't want them?

Nuget package update?

We just went live with our website on DXP we have been working on for the past 6 months.

Noticed the issue from PR #14`is acually a problem. I was aware paying notice to this at the time the issue was open (march). But I can see there has been no update of the nuget packages since January. When are you planning to update them on the Optimizley Feed?

Default value for Redirect Type

Hi! Would like to propose an enhancement. Make it possible to select default value in the Redirect drop-down in the GUI.
We use Permanent almost all of the time so would be nice to have it as the default value.

image

Problem installing from optmizely nuget feed

Hi,

Since yesterday we are having problems installing this package from nuget.optmizely.com. The main package is fine but when it tries to get the admin package we see an error page (which makes nuget fail and stop the process instead of trying to retrieve it from nuget.org).

The install says the url below fails.

https://api.nuget.optimizely.com/v3/package/geta.notfoundhandler.admin/index.json

If I browse to it I get this page.

image

Other packages works fine though, even other packages that doesn't exist work fine. It is the same error when trying locally or from our build agent on Azure DevOps.

Has the admin package been uploaded to nuget.optimizely.com recently but isn't published or something? If not, could we maybe have it published there as well so we can get all the packages from the same feed?

Update redirects in a load-balanced environment

The previous 404handler used EPiServer.CacheManager but the new implementation does not rely on this functionality to update instances in a load-balanced environment. This functionality is essential for the handler in Optimizely DXP environments.

Functionality to update all instances when redirects are added or removed can be implemented with the Event API

Package uses outdated versions of JQuery and Bootstrap with vulnerabilities

Hello,

We use the GETA Not Found Handler on a number of our client builds. Recently we had a penetration test and they highlighted vulnerabilities with order 3rd party resources used by the GETA Not Found Handler tool. The penetration tester understood that the functionality was locked behind a user login so the risk was downgraded to medium.

The following is the feedback we received.

Using the Burpsuite scanner, we detected the use of jquery version 3.2.1.slim.min at
/EPiServer/Geta.NotFoundHandler.Optimizely/container, (<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js")
which has the following vulnerabilities:

  • CVE-2019-11358: jQuery before 3.4.0, as used in Drupal, Backdrop CMS, and other products, mishandles jQuery.extend(true, {}, ...) because of Object.prototype pollution
  • CVE-2020-11022: Regex in its jQuery.htmlPrefilter sometimes may introduce XSS
  • CVE-2020-11023: Regex in its jQuery.htmlPrefilter sometimes may introduce XSS

We also detected the use of bootstrap version 4.0.0 (<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css")>), which has the following vulnerabilities:

We were not able to identify any XSS vulnerabilities in the time allowed, however, we have observed XSS vulnerabilities in other sites that have reported this vulnerability – especially those that use the tooltip/popover function.

SEO Sitemaps Tab not showing in CMS after update

The SEO Sitemaps tab was not showing in our DXP environment after updating beyond version 1 (both 2.5.0 and 3.0.x):
image

After alot of digging we finally realized that the WebAdmins group needs to be assigned to the user now, not just the Adminstrators group. This brough the Sitemaps tab back:
image

Just thought this might be helpful to someone in the future.

Build warning

After installing Geta.NotFoundHandler.Optimizely 1.0.0-rc i get the following warning when building:

Geta.NotFoundHandler.Optimizely 1.0.0-rc depends on Geta.NotFoundHandler.Admin (>= 1.0.0-rc) but Geta.NotFoundHandler.Admin 1.0.0-rc was not found. An approximate best match of Geta.NotFoundHandler.Admin 1.0.0 was resolved.

.Net 5 version of 5.0.1

Will there be a .Net 5 version of the v5 build, like you did for the v4 build? e.g. 5.5.1?

Feature Request: Improved table filtering/sorting

Here are some improvement suggestions for making the plugin simpler to administer.
Found it hard to cleanup redirects caused by #71 since the search gets reseted and you can't order the colums as well.

  • After deleting a post, the current view gets reset. The current state (filter/query) should be "preserved" (with the deleted post of course missing)
  • One should be able to order and/or filter the columns (for Redirects: Old URL | New URL | Wildcard | Redirect Type) to be make it easier to find common redirects.
  • Add a possibility to check multiple posts for deletion

redirect loop

example defined redirect:

   <url>
      <old redirectType="Permanent">/some-kind-of-old-url/p11111111122</old>
      <new>/new-url?code=new-code</new>
    </url>

if /new-url?code=new-code returns 404 redirect loop is formed until 414 occurs

Configure methods missing in 2.0.0

I just installed Geta.NotFoundHandler.Optimizely version 2.0.0. I tried following the configuration guide but AddNotFoundHandler and AddOptimizelyNotFoundHandler methods are not available in this new version. If I downgrade to 1.1.1 I am able to access the methods and therefor add it to the cms.

NotFoundHandler redirecting to wrong URL in case of query string

Given rules:

Old URL = /search/ps_90/s_13?kw=oakley+radar+ev
New URL = /search-page/?query=oakley+radar+ev

Test case:

Visited URL: /search/ps_90/s_13?kw=oakley+radar+ev
Expected result: redirect to /search-page/?query=oakley+radar+ev
Actual result: redirect to /search-page//ps_90/s_13?kw=oakley%20radar%20ev&query=oakley

NullReferenceException on redirect

Hi,

After upgrading from V1.0.4 to V5.0.1, whenever I visit an non-existing link, instead of redirecting to /404, a NullReferenceException is thrown:
System.NullReferenceException: Object reference not set to an instance of an object. at Geta.NotFoundHandler.Core.Redirects.CustomRedirectCollection.<>c.<FindInProviders>b__14_1(RewriteResult rewriteResult) at System.Linq.Enumerable.WhereSelectEnumerableIterator'2.MoveNext() at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable'1 source, Boolean& found) at Geta.NotFoundHandler.Core.Redirects.CustomRedirectCollection.FindInProviders(String oldUrl) at Geta.NotFoundHandler.Core.Redirects.CustomRedirectCollection.Find(Uri urlNotFound) at Geta.NotFoundHandler.Core.RequestHandler.HandleRequest(Uri referer, Uri urlNotFound, CustomRedirect& foundRedirect) at Geta.NotFoundHandler.Core.RequestHandler.Handle(HttpContext context) at Geta.NotFoundHandler.Infrastructure.Initialization.NotFoundHandlerMiddleware.InvokeAsync(HttpContext context, RequestHandler requestHandler) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context) at Web.Startup.<>c.<<Configure>b__4_0>d.MoveNext()

Perhaps this is unrelated, but Ive noticed some of the added redirects have a redirect type of 0. When I visit one of these links, the same error is thrown. If I go into the database and change this to 301/302, the error dissapears, and the page is redirected correctly.

Has anything changed between V1.0.4 and V5.0.1 that I am also supposed to change in the code?

Redirect type not set when adding from Suggestions

When adding a redirect from Suggestions, the redirect type is set to 0.
I think it would be better to either set a default value of temporary or permanent. An alternative could be to add the possibility to set the type when adding the redirect from Suggestions.

bild

MissingMethodException: Method not found: 'Int32 X.PagedList.IPagedList`1.get_Count()'.

When visiting "Suggestions" section.

Version: 3.0.1

System.MissingMethodException: Method not found: 'Int32 X.PagedList.IPagedList`1.get_Count()'.
   at AspNetCoreGeneratedDocument.Areas_Geta_NotFoundHandler_Admin_Pages_Suggestions.ExecuteAsync()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
   at AspNetCoreGeneratedDocument.Areas_Geta_NotFoundHandler_Admin_Pages_Suggestions.ExecuteAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAdapter.ExecuteAsync()
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|22_0(ResourceInvoker invoker, IActionResult result)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Mediachase.Commerce.Anonymous.Internal.AnonymousIdMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Feature Request: Add CSV as an additional Import/Export format

During out onboarding process for new Optimizely Clients, we either receive excel or csv files or our SEO team will create one as part of mapping their previous content onto the new content structure within an Optimizely build. Where clients have had a significant number of redirects within a given CMS (~10,000) they have also been known to export those redirects in order to review them in a human readable manner.

Feature Request: Regex Redirects

Hi,

We're looking to implement regex handling in the redirect paths and wanted to reach out to see if this was a feature you were working on already? Otherwise are you happy for us to implement for our solution and offer this is in a pull request once we've completed the feature if you'd like to incorporate it into your package?

No confirmation message when adding new redirect

Hi! We've successfully updated from the old handler version to Optimizely CMS12 version. But editors complain they don't see a confirmation message when adding new redirects. Such message was displayed earlier and now it is more confusing whether the action finished with success.

Steps to reproduce:

  1. Go to NotFound handler Redirects section
  2. Set the Old URL, the New URL and click the Add button

Expected: redirect is added and a confirmation message is displayed that the operation is successful

Actual: redirect is added, but no visible status is displayed in UI

Suggestion data implementation design is flawed

Performance for the paginated list is very poor. It will quickly show. Our website (which was a migration with new URL structure ... but with many redirect) has now run for approx. 1½ month. We have ~4400 rows returned on GetAllSuggestionCount. For all 4400 it will need to run a "Sub query" to get referrers (count). We have past the point where it now times out on DXP (prod). Locally the query on a fast pc takes more than a minute.

The problem is the way referrer is being queries as a subquery. That means regardless of pagination (which page you want to see) all old URLs are being queried for referrers. For now Suggestions is useless for medium-large sized websites if not regularly cleaned up (delete all suggestions) :)

Suggested solution:
Introduce api endpoint for retrieving referrers and not include referrers in GetAllSummaries(). Clicking on referrers on the list in admin is also not something you do for all rows so the info could be fetched on a need basis.
Endpoint should have the same protection as the admin

We might be able to contribute ... just clarifying that.

YARP and NotFoundHandler pipeline processing order

I have an installation using both the NotFoundHandler and Yarp reverse proxy. The NotFoundHandler is being loaded in the ConfigureServices method and Yarp is loaded in the Application builder Configure method.

Everything works as expected until you try to redirect a URL that also needs to be reverse proxied. In this instance, the reverse proxy gets the URL before the NotFoundHandler and this results in a 404. The redirector should change the path and then let the reverse proxy alter the URL, but the NotFoundHandler never gets called.

For example:

This is the NotFoundHandler URL that is mapped

Then the reverse proxy needs to adjust the browser URL to look like this:

The reverse proxy sees:

before the redirector can change the URL - even though it should be coming first in the pipeline.

Geta.NotFoundHandler.Optimiziely version 5.0.4
Yarp.ReverseProxy version 2.0.0
EPiServer.CMS version 12.13.2

Exception in handler when response has started

Hi! The middleware throws exception when the response has started when it tries to clear it. I can make a PR if you give me permissions.

Steps to reproduce:
HttpContext.Response.HasStarted is true when the middleware executes

Ignore specific routes?

Hi!

It would be a nice feature to be able to ignore specific routes. In our webapplication we proxy some requests to another API that may deliver 404 responses which we dont want the handler to interfere with. Is there an easy way to accomplish this?

Automatic Redirects: Trailing slash added to Old/New URLs

We are using the automatic redirects feature for a site, and it seems that a trailing slash is added to all the redirects, like so:
image

It works great when the slash is present in the old url, but when using the old url without the trailing slash, we get a 404. Most users are accessing these URLs without a trailing slash, unless they're part of a path. Is there a way to tweak the behavior so that the old/new URLs can be added without this trailing slash? Even better, add two entries to account for both trailling slash & without?

New redirects do not work on CMS 12 / DXP

We have a multi site / multi language instance on Optimizely DXP running .net 6, CMS 12 and with GETA NotFoundHandler version 5.0.1 installed.
On the prod instance we experience that new redirects are not working as expected. Instead of redirecting to the specified url we see our 404 page.
We have experienced this in a previous version where the redirect cache where not updated on other app instances.
I am not sure this is the same issue. It might be.
Older redirects works as expected

Issue: Relative URL without wildcard resulting in an infinite redirect

We have encountered an issue with relative redirects.
A client has a people page which is organised like so:

/en/people/ (folder-page)
/en/people/person-one/
/en/people/person-two/
/en/people/experts/

How to Reproduce:

Version: 5.0.5
Old Url: /en/people/
New Url: /en/people/experts
Wildcard: false

Url Attempted: /en/people/fneksnfa
Expected Result: 404
Actual Result: Infinite redirect with /expert/ repeatedly added to the URL

e.g.
https://prod.client-name.com/en/people/experts//experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/experts/fneksnfa

Work Around:
Enter these rules as absolute URLs

Would it be possible to define a behaviour rather than being wildcard on/off to be a behaviour choice:

For example, if we have a redirect: /a to /b, then:

Match All (existing wildcard on) : it will redirect /a/1 to /b
Partial Replace (existing wildcard off) : it will redirect /a/1 to /b/1
Exact Match: it will redirect /a to /b, /a/1 will remain as /a/1

What are the scheduled jobs?

Hi,

I just noticed these two scheduled jobs in the cms.

image

What are these doing exactly? Should we activate these?

Thanks
Dan

NotFoundHandler menu is not available within CMS

After adding the necessary packages and configuration in StartUp file, not able to access the NotFoundHandler menu in CMS. CMS version installed is EPiServer.CMS(12.17.0) and packages installed are Geta.NotFoundHandler, Geta.NotFoundHandler.Admin and Geta.NotfoundHandler.Optimizely version 5.0.6. Added necessary configuration in appSettings.json and the custom error page is also not working.
Please help if there is any missing configuration to make it work.

"IndexOutOfRangeException: Cannot find table 0." in UI for Regex Redirects (Beta)

Just upgraded from v3.1.0 to v5.0.1.
When navigating to the "Regex Redirects (Beta)" area of the admin UI, I get this error:

System.IndexOutOfRangeException: Cannot find table 0.
   at System.Data.DataTableCollection.get_Item(Int32 index)
   at Geta.NotFoundHandler.Data.SqlDataExecutor.ExecuteQuery(String sqlCommand, IDbDataParameter[] parameters)
   at Geta.NotFoundHandler.Data.SqlRegexRedirectRepository.GetAll()
   at Geta.NotFoundHandler.Core.Providers.RegexRedirects.MemoryCacheRegexRedirectRepository.<GetAll>b__6_0(ICacheEntry cacheEntry)
   at Microsoft.Extensions.Caching.Memory.CacheExtensions.GetOrCreate[TItem](IMemoryCache cache, Object key, Func`2 factory)
   at Geta.NotFoundHandler.Core.Providers.RegexRedirects.MemoryCacheRegexRedirectRepository.GetAll()
   at Geta.NotFoundHandler.Admin.Areas.Geta.NotFoundHandler.Admin.RegexModel.FindRedirects()
   at Geta.NotFoundHandler.Admin.Areas.Geta.NotFoundHandler.Admin.RegexModel.Load()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.VoidHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext httpContext, Boolean retry)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

So it seems like the table for the regex redirects didn't get added/updated? Is there a way to re-initialize the table?

Suggestions table gets out of control

  1. After less than 1 month in production, Suggestions table has grown to 500 000 records.
  2. There should be a way to exclude certain URLs from suggestions, such as health probes (/episerver/health or similar).

IndexOutOfRangeException

i have installed Geta.NotFoundHandler.Optimizely 1.0.0-rc
in startup i have added:

in ConfigureServices:
var connectionString = _configuration.GetConnectionString("EPiServerDB");
services.AddNotFoundHandler(o => {
o.UseSqlServer(connectionString);
});
services.AddOptimizelyNotFoundHandler();

in Configure:
app.UseNotFoundHandler();

When running i get the following error when the app.UseNotFoundHandler() line is reached:

System.IndexOutOfRangeException
HResult=0x80131508
Message=Cannot find table 0.
Source=System.Data.Common
StackTrace:
at System.Data.DataTableCollection.get_Item(Int32 index)
at Geta.NotFoundHandler.Data.SqlDataExecutor.ExecuteQuery(String sqlCommand, IDbDataParameter[] parameters)
at Geta.NotFoundHandler.Data.SqlRedirectRepository.GetAll()
at Geta.NotFoundHandler.Core.Redirects.DefaultRedirectsService.GetAll()
at Geta.NotFoundHandler.Core.Redirects.RedirectsInitializer.GetCustomRedirects()
at Geta.NotFoundHandler.Core.Redirects.RedirectsInitializer.Initialize()
at Geta.NotFoundHandler.Infrastructure.Initialization.ApplicationBuilderExtensions.UseNotFoundHandler(IApplicationBuilder app)

SQL error for logging url suggestions

I got this SQL error when logging url suggestions:

`Geta.NotFoundHandler.Data.SqlDataExecutor: Error: An error occurred in the ExecuteSQL method with the following sql: INSERT INTO [dbo].[NotFoundHandler.Suggestions]
(Requested, OldUrl, Referer)
VALUES
(@requested, @oldurl, @referer)

System.ArgumentException: The SqlParameter is already contained by another SqlParameterCollection.
at Microsoft.Data.SqlClient.SqlParameterCollection.Validate(Int32 index, Object value)
at Microsoft.Data.SqlClient.SqlParameterCollection.Add(Object value)
at Geta.NotFoundHandler.Data.SqlDataExecutor.CreateCommand(SqlConnection connection, String sqlCommand, IDbDataParameter[] parameters)
at Geta.NotFoundHandler.Data.SqlDataExecutor.ExecuteNonQuery(String sqlCommand, IDbDataParameter[] parameters)`

Modules folder to copied to output

Hi,

I'm having an issue wherein the ContentFiles for the package are not getting published.

I've noticed that the nuspec file for this package does not direct the 'ContentFiles' (modules/_protected/Geta.NotFoundHandler.Optimizely/module.config) to be included in the output (i.e. 'copyToOutput' is not declared). Could this be the issue?

Thanks

Dan

SQL Errors at boottime

Hello,

I have a .NET6 Alloy based project.

I upgraded Geta-NotFoundHandler from the version 3.0.0 to the latest one 5.0.1 and I noticed few SQL errors when I launch the site. I seems it tries create an already existing SQL Table.

This is not blocking as it doesn't seem to have any side effect so far by I just wanted to shared the issue:

_fail: Geta.NotFoundHandler.Data.SqlDataExecutor[0]
      An error occurred in the ExecuteScalar method with the following sql: SELECT *
                       FROM INFORMATION_SCHEMA.TABLES
                       WHERE TABLE_SCHEMA = 'dbo'
                       AND  TABLE_NAME = '[dbo].[NotFoundHandler.RegexRedirects]'
      System.NullReferenceException: Object reference not set to an instance of an object.
         at Geta.NotFoundHandler.Data.SqlDataExecutor.ExecuteScalar(String sqlCommand)_
_fail: Geta.NotFoundHandler.Data.SqlDataExecutor[0]
      An error occurred in the ExecuteSQL method with the following sql: CREATE TABLE [dbo].[NotFoundHandler.RegexRedirects] (
                                              [Id] [uniqueidentifier] NOT NULL,
                                              [OldUrlRegex] [nvarchar](2000) NOT NULL,
                                              [NewUrlFormat] [nvarchar](2000) NOT NULL,
                                              [OrderNumber] [int] NOT NULL,
                                              [TimeoutCount] [int] NOT NULL,
                                              [CreatedAt] [datetime] NOT NULL,
                                              [ModifiedAt] [datetime] NOT NULL,
                                              CONSTRAINT [PK_NotFoundHandlerRegexRedirects] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
                                              ) ON [PRIMARY]
      Microsoft.Data.SqlClient.SqlException (0x80131904): There is already an object named 'NotFoundHandler.RegexRedirects' in the database.
         at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
         at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
         at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
         at Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite)
         at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
         at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
         at Geta.NotFoundHandler.Data.SqlDataExecutor.ExecuteNonQuery(String sqlCommand, IDbDataParameter[] parameters)_

Thank you and have a good day,

Redirect with query string as new destination forms malformed URL

example defined redirect:

   <url>
      <old redirectType="Permanent">/some-kind-of-old-url/p11111111122</old>
      <new>/new-url?code=new-code</new>
    </url>

request 1:
incoming URL is: https://site/some-kind-of-old-url/p11111111122
redirected to: https://site/new-url?code=new-code
All is fine as expected

request 2:
incoming URL is: https://site/some-kind-of-old-url/p11111111122?additonalquerystring
redirected to: https://site/new-url?code=new-code?additonalquerystring
Malformed URL is created with two question marks

Unable to move or copy pages in CMS

CMS 12, DXP, multisite, multi language

We have enabled automatic redirects on our multisite, multi language setup in DXP. However when we do that we are unable to move or copy pages.
We get the error below when we copy/paste a page:
"10.5.3 Export/import error: [Importing content 92940_264303] Exception: Unterminated string. Expected delimiter: ". Path '[21].Type', line 1, position 2000.
Newtonsoft.Json.JsonReaderException: Unterminated string. Expected delimiter: ..."

We get the below error on startup:
"Job Geta.NotFoundHandler.Optimizely.Core.AutomaticRedirects.RegisterMovedContentRedirectsJob failed for the job '[Geta NotFoundHandler] Register content move redir' with jobId ='ec96abee-5da4-404f-a0c8-451c77ca4983'
Newtonsoft.Json.JsonReaderException: Unterminated string. ..."

It looks like the value in the Urls column in table [NotFoundHandler.ContentUrlHistory] is too large for the column so the entire serialized object is not saved correctly.

This means that we cannot use automatic redirects at the moment.

Newly added re-directs are not re-directing.

Hi,
We have been using the notFoundHandler in Optimizely for a while now to create re-directs with no issue.
Recently, the re-directs that we are adding are not actually re-directing.

I have raised a ticket with Optimizely support who have suggested I contact the contributors of this package directly.
Any advice on how I could debug this? or is there any documentation that I could use related to this issue?

Re-directs that were added in the past are still working. However, if we try to add new re-directs, they do not actually re-direct when testing.

Old working re-direct: https://www.jotun.com/no/no/b2c/how-to/video/how-to-maintain-teak-details-on-boat.aspx > https://www.jotun.com/no-no/decorative/yachting/how-to/how-to-maintain-teak
The above example re-directs from the old url (left of >) to the new url.

New broken re-direct: https://www.jotun.com/no-no/decorative/professional/architects-downloads > https://www.jotun.com/no-no/decorative/professional/farger/jotun-digital-colour-palette
The above example will just direct the user the the old url (left of >)

Geta.NotFoundHandler.Optimiziely version = 5.01
Geta.NotFoundHandler.Optimiziely.Commerce version = 5.01

EPiServer.CMS Version 12.7.0
EPiServer.Commerce Version 14.4.0

Please let me know if you need any more information.

Status code 401 for /GetaNotFoundHandlerAdmin on Optimizely DXP

We are using the NotFoundHandler for a site in Optimizely DXP. We have recently updated to version 5.0.1.0 because of a security issue in the earlier version we used. We now get a 401 on the iframe url [DXP-url]/GetaNotFoundHandlerAdmin
It is .NET 6, CMS 12
We have mapped role settings in appsettings where we map from an openid provider role to CmsAdmins and Adminstrators but we do not get access to the plugin. We have access to everything else that we should when we have CmsAdmin and Adminstrators roles.
Our configuration in the Startup class is as follows:
services.AddNotFoundHandler(o =>
{
o.UseSqlServer(_configuration.GetConnectionString("EPiServerDB"));
o.HandlerMode = FileNotFoundMode.On;
o.IgnoredResourceExtensions = new[] { "jpg", "gif", "png", "css", "js", "ico", "swf", "woff", "svg" };
o.Logging = LoggerMode.On;
o.LogWithHostname = true;
},
policy =>
{
policy.RequireRole("Administrators", "CmsAdmins");
});
policy was removed for testing purposes. Didn't help.

Any suggestions? Are we missing something in the configuration?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.