Giter Site home page Giter Site logo

Comments (19)

deanmarcussen avatar deanmarcussen commented on August 23, 2024 1

The issue is likely .NET 6 Preview 4 related

I can't say yet whether it's a bug in the new date handling in preview 4, or just a breaking change, but we've also had a limited report, which I haven't had time to look into further, which indicated issues parsing the yaml metadata file during head requests.

I say limited as all we got was a log file, indicating some parse errors.

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024 1

Ok, I'll try that this evening (in around 7h :-D).

Cannot really do that right away as I'm trying to integrate IS in big project, but I'll try to do a minimal solution ;-)

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024 1

TL;DR: I feel so useless... It was an issue with .NET 6 - preview 3...

I tried on a VM in order to isolate some scenario.
This VM didn't have .NET 6 installed, so I installed the preview 4 and it works with .NET 5 and .NET 6.

So I tried again on my main machine, and it worked with .NET 5 but not with .NET 6.
A difference was that I had the preview 3 installed on my main machine so I updated it to .NET 6 preview 4 and now it works...

Sorry for the waste of time :-$

from imagesharp.web.

brianpopow avatar brianpopow commented on August 23, 2024 1

TL;DR: I feel so useless... It was an issue with .NET 6 - preview 3...

I tried on a VM in order to isolate some scenario.
This VM didn't have .NET 6 installed, so I installed the preview 4 and it works with .NET 5 and .NET 6.

So I tried again on my main machine, and it worked with .NET 5 but not with .NET 6.
A difference was that I had the preview 3 installed on my main machine so I updated it to .NET 6 preview 4 and now it works...

Sorry for the waste of time :-$

dont worry, this happens to everyone. Good that you have figured it out.

from imagesharp.web.

JimBobSquarePants avatar JimBobSquarePants commented on August 23, 2024

Please add your exact configuration.

Please also bear in mind that this is an open source project and unhelpful (snarky) comments regarding documentation are not welcome.

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024

Hi,

First of all, I'd like to mention that my remark about the document was not intended as a pun. It was just a mention to indicate that the document was a bit light (for example: there's not much about how to configure a custom file provider). However, accept my apologies if you took it wrong, it was not my intention :-)

What more do you need about the configuration?

I'm currently debugging the code source to find out what could be the issue.

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024

Here is what I gathered so far.

In the middleware, there is this code:

(IImageCacheResolver ImageCacheResolver, ImageCacheMetadata ImageCacheMetadata) cachedImage = await
    CacheResolverLru.GetOrAddAsync(
        key,
        async k =>
        {
            IImageCacheResolver resolver = await this.cache.GetAsync(k);
            ImageCacheMetadata metadata = default;
            if (resolver != null)
            {
                metadata = await resolver.GetMetaDataAsync();
            }

            return (resolver, metadata);
        });

When this code is executed for a new image, as there are nothing in the cache for it, it returns "default".
In metaData, there is the property CacheLastWriteTimeUtc.
This one gets initialized on the DateTime.MinValue.

However, when calling:

await this.SendResponseAsync(imageContext, key, readResult.CacheImageMetadata, readResult.Resolver);

The following call is done:

imageContext.ComprehendRequestHeaders(metadata.CacheLastWriteTimeUtc, metadata.ContentLength);

Where metadata.CacheLastWriteTimeUtc gets implicitly casted into a DateTimeOffset and it looks like that casting DateTime.MinValue to a DateTimeOffset does not work (on my system).

I also created a small console app with the following code:

var a = (DateTimeOffset)DateTime.MinValue;

I tried executing that and it failed with the same issue.

Note that I tried executing the console app with .NET 2.1, 3.1, 5.0 and 6.0 and I get the same issue each time.

This seemed pretty weird to me though as I should not be the only one to get the error, so in order to be sure, I tried to execute the same code with C# fiddle and... I don't have the error o_O

So it seems to be something related to my system but I have no idea what it could be.

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024

Holy dates...

I just tried this:

var b = DateTime.MinValue.AddHours(1);
var a = (DateTimeOffset)b;

And this works.
I'm Belgian so my timezone if "UTC + 1", so I guess that when DateTime.MinValue gets converted, it's like translated in "0" - one hour which is why it works when adding one hour...

So this means that the issue could occur on every system with a timezone offset, right?

from imagesharp.web.

brianpopow avatar brianpopow commented on August 23, 2024

It seems this issue will occur for all timezone which are UTC + x:

See the documentation remarks of DateTimeOffset:

"This means that a DateTimeOffset value whose date and time are close to the minimum range, but whose offset is positive, may throw an exception. For example, the value 1/1/0001 1:00:00 AM +02:00 is out of range because it is one hour earlier than MinValue when it is converted to UTC."

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024

Same conclusion here.
I tried replacing the line by:

imageContext.ComprehendRequestHeaders(metadata.CacheLastWriteTimeUtc == DateTime.MinValue ? DateTime.UnixEpoch : metadata.CacheLastWriteTimeUtc, metadata.ContentLength);

And the issue does not occur anymore.
However, now, I have another issue where the cache file is not written onto the disk, might be related (or not).

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024

The issue was not related.

In "ImageCacheMetadata", there is this method:

public async Task WriteAsync(Stream stream)
{
    var dictionary = this.ToDictionary();

    using var writer = new StreamWriter(stream, Encoding.UTF8);
    foreach (KeyValuePair<string, string> keyValuePair in dictionary)
    {
        // TODO: string.Create
        await writer.WriteLineAsync($"{keyValuePair.Key}:{keyValuePair.Value}");
    }

    writer stream.FlushAsync();
}

However, the file was never written for me.
I replaced the last line by:

await stream.FlushAsync()

And now it works, the file is correctly written and the image is correctly returned.

However, it seems pretty weird (once again haha) as, from what I gather on Internet, flushing the StreamWriter should flush the FileStream. I even read that normally, closing the stream (via the using) should flush it...

Anyway, with the two changes I made above, the library seems to work and return me the expected image. Now, I'm not sure that my fix were very clean (I guess flushing the FileStream from the PhysicalFileSystemCache would be cleaner), I think you guys should be able to fix it in a better way now that you know the root causes?

Thanks

from imagesharp.web.

brianpopow avatar brianpopow commented on August 23, 2024

I have trouble getting a simple reproducible example done for this. I can reproduce the issue with the DataTimeOffset cast, but I cannot get a simple sample together with ImageSharp.Web.

@ssougnez could you please provide a complete minimal example, maybe a complete minimal sample project as a zip would be helpful.

from imagesharp.web.

JimBobSquarePants avatar JimBobSquarePants commented on August 23, 2024

@brianpopow there’s a sample project in the repo. Would you be able to use that?

The unit tests use an in-memory test server so maybe we can create an appropriate replication scenario there.

from imagesharp.web.

brianpopow avatar brianpopow commented on August 23, 2024

@JimBobSquarePants I have used that to reproduce the issue without seeing an error. Im at GMT+2, so the issue should happen.
I also tied .net 6.0 without an issue. There must be something different to what @ssougnez is doing.

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024

I'm back :-)

Here is a very minimal repro of the issue.
If I launch this with Visual Studio, then access "/ad.png", it works.
If I access "/ad.png?width=10", then I have the DateTimeOffset issue.
I tried changing my timezone to UTC, then I got a different error because when converting the DateTimeOffset in a FileWriteTime, it says that it is not a valid Win32 file time. This is why I used "UnixEpoch" in my dirty quick fix above.

It seems that as such, the package is not supported on Windows (maybe Linux supports file time equals to DateTime.MinValue).

I didn't tried my "fixed" version of the DLL to see if the second issue (with the Flush) occurs as well.

And btw, @brianpopow I tried changing my timezone to UTC + 2 and also got the issue. Weird weird...

WebApplication7.zip

from imagesharp.web.

brianpopow avatar brianpopow commented on August 23, 2024

@ssougnez thanks for providing the repro, but i cannot reproduce the issue even with it. It works without an issue, when i do as you said.

from imagesharp.web.

ssougnez avatar ssougnez commented on August 23, 2024

Well... I didn't read it but I guess it's not a coincidence :-D

https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/

from imagesharp.web.

sheastrickland avatar sheastrickland commented on August 23, 2024

When this code is executed for a new image, as there are nothing in the cache for it, it returns "default".
In metaData, there is the property CacheLastWriteTimeUtc.
This one gets initialized on the DateTime.MinValue.

However, when calling:

await this.SendResponseAsync(imageContext, key, readResult.CacheImageMetadata, readResult.Resolver);

The following call is done:

imageContext.ComprehendRequestHeaders(metadata.CacheLastWriteTimeUtc, metadata.ContentLength);

Where metadata.CacheLastWriteTimeUtc gets implicitly casted into a DateTimeOffset and it looks like that casting DateTime.MinValue to a DateTimeOffset does not work (on my system).

I also created a small console app with the following code:

var a = (DateTimeOffset)DateTime.MinValue;

I tried executing that and it failed with the same issue.

Note that I tried executing the console app with .NET 2.1, 3.1, 5.0 and 6.0 and I get the same issue each time.

Have the exact same issue, and replicated all the above @ssougnez.

A cache miss, which returns a default ImageCacheMetadata, which has a CacheLastWriteTimeUtc of default DateTime, which has a DateTime with Kind set to Unspecified.

When calling ComprehendRequestHeaders(, there's an implicit cast from DateTime, to DateTimeOffset, c# implicit cast below:

	public static implicit operator DateTimeOffset(DateTime dateTime)
	{
		return new DateTimeOffset(dateTime);
	}

... which callsthe DateTimeOffset ctor:

	public DateTimeOffset(DateTime dateTime)
	{
		TimeSpan offset = ((dateTime.Kind == DateTimeKind.Utc) ? new TimeSpan(0L) : TimeZoneInfo.GetLocalUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime));
		_offsetMinutes = ValidateOffset(offset);
		_dateTime = ValidateDate(dateTime, offset);
	}

The culprit is TimeZoneInfo.GetLocalUtcOffset on our timezones we have a positive offset, which gets subtracted off the DateTime.MinValue and breaks the rules in ValidateDate :)

		long num = dateTime.Ticks - offset.Ticks;
		if (num < 0 || num > 3155378975999999999L)
		{
			throw new ArgumentOutOfRangeException("offset", SR.Argument_UTCOutOfRange);
		}

Changing ImageSharpMiddleware.SendResponseAsync to specify the kind will get around this issue (not pretty, but functional):

	var adjustedCacheLastWriteTimeUtc = (metadata.CacheLastWriteTimeUtc == default && metadata.CacheLastWriteTimeUtc.Kind != DateTimeKind.Utc)
			? DateTime.SpecifyKind(metadata.CacheLastWriteTimeUtc, DateTimeKind.Utc)
			: metadata.CacheLastWriteTimeUtc;

imageContext.ComprehendRequestHeaders(adjustedCacheLastWriteTimeUtc, metadata.ContentLength);

from imagesharp.web.

sheastrickland avatar sheastrickland commented on August 23, 2024

I don't have the "privilege" to re-open this one πŸ˜€
I can create a new issue from this one, but seems better to just keep this one alive.

from imagesharp.web.

Related Issues (20)

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.