ligershark / WebOptimizer

A bundler and minifier for ASP.NET Core
Apache License 2.0
757 stars 113 forks source link

Exception: Value cannot be null. (Parameter 'path1') #172

Open vukasinpetrovic opened 3 years ago

vukasinpetrovic commented 3 years ago

I followed the documentation and created css bundle but I get the exception "Value cannot be null. (Parameter 'path1')" when I try to access the created bundle file. One thing I noticed is that it works if I set UseContentRoot(), but then css files from libraries (ie. fontawesome) cannot find required files that they need because url is now in format domain.com/wwwroot/css/bundle.cs.

.NetCore: 3.1 WebOptimizerCore: 3.0.307

image

Stack trace

at System.IO.Path.Combine(String path1, String path2) at WebOptimizer.CssFingerprinter.Adjust(String content, IFileInfo input, IWebHostEnvironment env) at WebOptimizer.CssFingerprinter.ExecuteAsync(IAssetContext config) at WebOptimizer.Asset.ExecuteAsync(HttpContext context, IWebOptimizerOptions options) at WebOptimizer.AssetBuilder.BuildAsync(IAsset asset, HttpContext context, IWebOptimizerOptions options) at WebOptimizer.AssetMiddleware.HandleAssetAsync(HttpContext context, IAsset asset, WebOptimizerOptions options) at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

Elimi81 commented 3 years ago

I'v fought with the same problem myself and fixed it by editing the css fingerprinter in my fork of the repository: https://github.com/Elimi81/WebOptimizer/tree/dev (dev-branch). But I don't have enough time / knowledge of this project to make a pull request for the main repo. In other words I have no idea what my changes might break somewhere else. But for us this change corrects the problem you and we encountered. Feel free to try it out.

limsbeheer commented 2 years ago

We experience the same exception when setting the TargetFramework to net6.0. Works fine with TargetFramework net5.0.

Ahoapap commented 2 years ago

We experience the same exception when setting the TargetFramework to net6.0. Works fine with TargetFramework net5.0.

Same on our conversion from .net5.0 to .net6.0

d-sky commented 2 years ago

We experience the same exception when setting the TargetFramework to net6.0. Works fine with TargetFramework net5.0.

The same on my project. After setting target framework to 6.0, getting error message, and no bundle produced.

Robo356 commented 2 years ago

Fixed it by adding the folder wwwroot to the project (empty for me), move resources outside this folder and use .UseContentRoot() extension.

jayb611 commented 2 years ago

it is font awesome creating issue. we need to put it separately,on CSHTML

dahari87 commented 2 years ago

Also here not working with .net6

ajkonkol commented 2 years ago

I also noticed this problem that started with .NET 6. I have been able to reduce the issue down to a bare minimum. Here's my CSS file (wwwroot\site.css) body { background: url(example.png); }

Here's my WebOptimizer configuration (in Program.cs): builder.Services.AddWebOptimizer(pipeline => { pipeline.AddCssBundle("/bundle.css", "site.css"); });

I also have a file named example.png in wwwroot. And that's it. With this minimal setup, I am unable to retrieve /bundle.css. I get the following error: System.ArgumentNullException: Value cannot be null. (Parameter 'path1') at System.IO.Path.Combine(String path1, String path2) at WebOptimizer.CssFingerprinter.Adjust(String content, IFileInfo input, IWebHostEnvironment env) at WebOptimizer.CssFingerprinter.ExecuteAsync(IAssetContext config) at WebOptimizer.Asset.ExecuteAsync(HttpContext context, IWebOptimizerOptions options) at WebOptimizer.AssetBuilder.BuildAsync(IAsset asset, HttpContext context, IWebOptimizerOptions options) at WebOptimizer.AssetMiddleware.HandleAssetAsync(HttpContext context, IAsset asset, WebOptimizerOptions options) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

So it appears that it's something to do with url()'s in the css.

ajkonkol commented 2 years ago

A few more observations: If I switch my local environment to Production (ASPNETCORE_ENVIRONMENT variable), then the problem goes away. I notice that when running in Production mode, the IHostEnvironment.WebRootFileProvider is a PhysicalFileProvider. When running in Development mode, the IHostEnvironment.WebRootFileProvider is a CompositeFileProvider.

I can work around this issue by using the following code, which forces WebOptimizer to use a PhysicalFileProvider: pipeline.AddCssBundle("/bundle.css", "site.css").UseFileProvider(new PhysicalFileProvider(builder.Environment.WebRootPath));

michaellwest commented 2 years ago

In my case, after upgrading from .net 5 to .net 6 the issue appeared. I was able to fix the issue by changing the path in the scss for images.

Imagine a style like the following:

[type=checkbox] + label {
    background-image: url(../images/icons/button-box.png);
}

The path was updated to the following where there is a leading slash:

[type=checkbox] + label {
    background-image: url(/../images/icons/button-box.png);
}
a-a-k commented 2 years ago

is the library supported by someone?

a-a-k commented 2 years ago

I'v fought with the same problem myself and fixed it by editing the css fingerprinter in my fork of the repository: https://github.com/Elimi81/WebOptimizer/tree/dev (dev-branch). But I don't have enough time / knowledge of this project to make a pull request for the main repo. In other words I have no idea what my changes might break somewhere else. But for us this change corrects the problem you and we encountered. Feel free to try it out.

could you give a link to commit with the exact changes you did?

danielgreen commented 2 years ago

A few more observations: If I switch my local environment to Production (ASPNETCORE_ENVIRONMENT variable), then the problem goes away. I notice that when running in Production mode, the IHostEnvironment.WebRootFileProvider is a PhysicalFileProvider. When running in Development mode, the IHostEnvironment.WebRootFileProvider is a CompositeFileProvider.

I can work around this issue by using the following code, which forces WebOptimizer to use a PhysicalFileProvider: pipeline.AddCssBundle("/bundle.css", "site.css").UseFileProvider(new PhysicalFileProvider(builder.Environment.WebRootPath));

The issue affecting net6.0 appears to be fixed in 3.0.357

See PR #219

a-a-k commented 2 years ago

A few more observations: If I switch my local environment to Production (ASPNETCORE_ENVIRONMENT variable), then the problem goes away. I notice that when running in Production mode, the IHostEnvironment.WebRootFileProvider is a PhysicalFileProvider. When running in Development mode, the IHostEnvironment.WebRootFileProvider is a CompositeFileProvider. I can work around this issue by using the following code, which forces WebOptimizer to use a PhysicalFileProvider: pipeline.AddCssBundle("/bundle.css", "site.css").UseFileProvider(new PhysicalFileProvider(builder.Environment.WebRootPath));

The issue affecting net6.0 appears to be fixed in 3.0.357

See PR #219

great thanks for sharing that, but I'm still getting the error. what else have I to do to fix that?

danielgreen commented 2 years ago

great thanks for sharing that, but I'm still getting the error. what else have I to do to fix that?

Are you running on net6.0 and have you updated to the latest package from NuGet?

Could you share your startup code and the exception details and stack trace?

a-a-k commented 2 years ago

Yes, I updated the package up to 3.0.357 before the check + .NET 6

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.ArgumentNullException: Value cannot be null. (Parameter 'path1')
         at System.IO.Path.Combine(String path1, String path2)
         at WebOptimizer.CssFingerprinter.Adjust(String content, IFileInfo input, IWebHostEnvironment env)
         at WebOptimizer.CssFingerprinter.ExecuteAsync(IAssetContext config)
         at WebOptimizer.Asset.ExecuteAsync(HttpContext context, IWebOptimizerOptions options)
         at WebOptimizer.AssetBuilder.BuildAsync(IAsset asset, HttpContext context, IWebOptimizerOptions options)
         at WebOptimizer.AssetMiddleware.HandleAssetAsync(HttpContext context, IAsset asset, WebOptimizerOptions options)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

And that's interesting there a half-worked bundles, I mean some CSS bundles work as expected some others do not (fail with the exception above).

Need I share the full startup? I'm afraid there is a lot of unrelated stuff. Here is how I use WebOptimizer

// ConfigureServices
services.AddWebOptimizer(pipeline =>
{
    pipeline.AddCssBundles(env); // extension method to hide all these AddCssBundle
    pipeline.AddJsBundles(env); // same for js
});
...
// Configure
...
var fpo = new[]
{
    new FileProviderOptions
    {
        FileProvider = new PhysicalFileProvider(Path.Combine(env.WebRootPath, "Content/images")),
        RequestPath = "/images",
    },
    new FileProviderOptions
    {
        FileProvider = new PhysicalFileProvider(Path.Combine(env.WebRootPath, "Content/icons")),
        RequestPath = "/icons",
    },
};

app.UseStaticFiles();
app.UseWebOptimizer(env, fpo);
...

// Extension method
 public static IAssetPipeline AddCssBundles(this IAssetPipeline pipeline, IWebHostEnvironment webHostEnvironment)
{
    pipeline.AddCssBundle("/Content/css.css",
        "/Content/styles/bootstrap.min.css",
        "/Content/styles/animate.css",
        "/Content/styles/profile.css",
        "/Content/styles/liveview.css",
        "/Content/styles/buttons.css");
     ...
}
EmilAlipiev commented 2 years ago

@a-a-k have you ever found the solution? same problem with me after upgrading to .net 6. working fine on .net 5

a-a-k commented 2 years ago

@a-a-k have you ever found the solution? same problem with me after upgrading to .net 6. working fine on .net 5

not yet

TWolverson commented 2 years ago

I'm experiencing the same symptom (also newly on .net 6, upgrading an old application) with a different call stack (I am using .UseContentRoot())

ArgumentNullException: Value cannot be null. (Parameter 'path1') System.IO.Path.Combine(string path1, string path2) WebOptimizer.RelativePathAdjuster.ExecuteAsync(IAssetContext config) WebOptimizer.Asset.ExecuteAsync(HttpContext context, IWebOptimizerOptions options) WebOptimizer.AssetBuilder.BuildAsync(IAsset asset, HttpContext context, IWebOptimizerOptions options) WebOptimizer.AssetMiddleware.HandleAssetAsync(HttpContext context, IAsset asset, WebOptimizerOptions options) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

@ajkonkol's workaround didn't make any difference for me.

Looking at RelativePathAdjuster it appears that this version of the error is thrown from env.WebRootPath. Adding an empty wwwroot folder to my web app project "fixed" this. It may be worth noting that upgraded projects won't always have a web root, for whatever reason old versions of asp.net didn't require it. I can't find an unequivocal statement of whether this is now mandatory in asp.net core or not - if it isn't, this library probably shouldn't depend on it.

jacobpretorius commented 1 year ago

Same behavior still, you need at least an empty wwwroot folder for it to work with .net 6

ghost commented 1 year ago

I am using .Net 7 projects with no issues in the development environment. When I publish the app to IIS, I have the following issue

System.ArgumentNullException: Value cannot be null. (Parameter 'path1')
   at System.ArgumentNullException.Throw(String paramName)
   at System.IO.Path.Combine(String path1, String path2)
   at WebOptimizer.RelativePathAdjuster.ExecuteAsync(IAssetContext config)
   at WebOptimizer.Asset.ExecuteAsync(HttpContext context, IWebOptimizerOptions options)
   at WebOptimizer.AssetBuilder.BuildAsync(IAsset asset, HttpContext context, IWebOptimizerOptions options)
   at WebOptimizer.AssetMiddleware.HandleAssetAsync(HttpContext context, IAsset asset, WebOptimizerOptions options)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()
zaneclaes commented 10 months ago

@ghost this implies that your IWebHostEnvironment is providing a null value for WebRootPath. This is especially common in development environments with recent dotnet versions. There are various ways to fix, i.e.,

WebApplication app = builder.Build();
app.Environment.WebRootPath = "/some/absolute/path/is/best";
kcrandall commented 2 months ago
services.AddWebOptimizer(pipeline =>
{
    var provider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(env.WebRootPath);
    pipeline.AddCssBundle("/css/bundle.css", "css/**/*.css").UseFileProvider(provider);
    pipeline.AddJavaScriptBundle("/js/bundle.js", "js/*.js").UseFileProvider(provider);
},
option =>
{
    option.EnableCaching = true;
    option.CacheDirectory = $"{env.WebRootPath}/cache";
    option.EnableDiskCache = true; 
    option.EnableMemoryCache = true;
    option.AllowEmptyBundle = true;
});

this overcame it for me specifically setting option.CacheDirectory

someonestolemyusername commented 1 month ago

Thank you - I also worked around the bug with a similar workaround:

options.CacheDirectory = $"{builder.Environment.ContentRootPath}/obj/WebOptimizerCache";
options.EnableDiskCache = true;