NetSparkleUpdater / NetSparkle

NetSparkle is a C#, cross-platform, highly-configurable software update framework with pre-built UI for .NET developers compatible with .NET 4.6.2/.NET 6+, WinForms, WPF, and Avalonia; uses Ed25519 signatures. View basic usage here in the README and try the samples for yourself.
https://netsparkleupdater.github.io/NetSparkle/
MIT License
625 stars 85 forks source link

Relative URLs for Items #57

Closed christianerlinger closed 5 years ago

christianerlinger commented 5 years ago

Hi!

Sorry to bother you again; I have an issue with relative URLs for the items in the appcast.xml file.

As the appcast file for all servers would very much look the same I figured with relative paths they would be 100% be the same so I would be able to generate one appcast.xml file at build time, not for each server at install time.

The update mechanism works with absolute paths in the URLs of course.

My AppCast.xml would look like this:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
    <channel>
        <title>starter</title>
        <language>en</language>
        <item>
            <title>starter app version 21.0.2</title>
            <pubDate>2019.02.08 11:56:53 MEZ</pubDate>
            <enclosure url="installer.exe"
                       sparkle:version="21.0.3"
                       type="application/octet-stream"/>
        </item>
    </channel>
</rss>

The installer.exe is located in the very same Directory where the appcast.xml is located.

Now I instantiate Spakle like

Sparkle sparkle = new Sparkle("http://localhost/aliasmatch/appcast.xml", this.Icon, SecurityMode.Unsafe);
sparkle.CheckForUpdatesQuietly();
sparkle.HideReleaseNotes = true;
sparkle.SilentMode = Sparkle.SilentModeTypes.DownloadAndInstall;
sparkle.CustomInstallerArguments = "/VERYSILENT";
sparkle.RelaunchAfterUpdate = true;
sparkle.AboutToExitForInstallerRun += BeforeRunInstaller;
sparkle.CloseApplication += CloseApplication;

When an Upgrade is attempted I get an Exception:

System.UriFormatException
  HResult=0x80131537
  Message=Ungültiger URI: Das URI-Format konnte nicht bestimmt werden.
  Source=System
  StackTrace:
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   at System.Uri..ctor(String uriString)
   at NetSparkle.Sparkle.InitDownloadAndInstallProcess(AppCastItem item)
   at NetSparkle.Sparkle.Update(AppCastItem[] updates)
   at NetSparkle.Sparkle.OnWorkerProgressChanged(Object sender, ProgressChangedEventArgs e)
   at NetSparkle.Sparkle.<OnWorkerDoWork>d__208.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

(Sorry for the German Error Message; it basically tranlsates to invalid URI Format - as the Exception says ;-)).

I took a look at GetAbsoluteUrlString which should return an Absolute URL for a relative item url: https://github.com/Deadpikle/NetSparkle/#systemuri-getabsoluteurlstring

seems to be right; however; I looked further and in NetSparkle.cs Method InitDownloadAndInstallProcess

Line 1094 there is

Uri url = new Uri(item.DownloadLink);
[...]
_webDownloadClient.DownloadFileAsync(url, _downloadTempFileName);

Please correct me if I am wrong - but item.DownloadLink is a relative URL in my case - and the code should call GetAbsoluteUrl (or something similar)? Am I getting this right?

thanks & regards Christian

Deadpikle commented 5 years ago

Hi again,

No worries. It's not a bother.

Hmmm...release notes do use the GetAbsoluteURL function, but downloads don't, you're right.

The original macOS Sparkle project had a similar issue filed here: https://github.com/sparkle-project/Sparkle/issues/616. Their opinion was that it was something Sparkle shouldn't handle due to RSS standards, which makes sense to me. A public file should contain absolute URLs, basically, and https://validator.w3.org/feed/docs/warning/ContainsRelRef.html confirms that idea.

But I have to admit that relative URLs would make things easier, potentially. I'm a little torn, to be honest, because I like specs.

I'm going to go ahead and make the change for now just so that the software is consistent in how it handles URLs in the appcast (and changing the way release notes are pulled is a breaking change), but I am not promising this change will stay in an eventual X.0 version of NetSparkle. The better plan would be to generate multiple appcast.xml files for each server at build time with absolute URLs.

Thanks :)

Deadpikle commented 5 years ago

Should be fixed in b1bb3d1. Let me know if it doesn't work for you. NuGet package has been pushed but might take a few mins to propagate.

christianerlinger commented 5 years ago

Hi,

I understand - I have the possibility to generate per server appcast.xmls once you remove that feature, but for now as I am under time pressure I wanted to spare me that work ;-). Thanks for including that for now.

However; there is No luck for me; NetSparkle.New 0.16.1

System.UriFormatException
  HResult=0x80131537
  Message=Ungültiger URI: Das URI-Format konnte nicht bestimmt werden.
  Source=System
  StackTrace:
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   at System.Uri..ctor(String uriString)
   at NetSparkle.Sparkle.InitDownloadAndInstallProcess(AppCastItem item)
   at NetSparkle.Sparkle.Update(AppCastItem[] updates)
   at NetSparkle.Sparkle.OnWorkerProgressChanged(Object sender, ProgressChangedEventArgs e)
   at NetSparkle.Sparkle.<OnWorkerDoWork>d__208.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_1(Object state)
   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

as you might have guessed I am fairly new to .NET and C# - but an update of the nuget package plus a complete cleanup and the new version should be included into my build (I have been burnt by eclipse with similar problems), right? At least when looking into the dependend packages I also have 0.16.1 at my installation...

or am I doing something wrong?

best regards

Deadpikle commented 5 years ago

Hi,

I understand having time constraints, haha. Been there, done that. 😅

What version of .NET are you using?

I'm not able to replicate the problem using "installer.exe" as the item link and "http://localhost/aliasmatch/appcast.xml" when building from source.

Hm. It's entirely possible I did a dumby and uploaded the wrong thing to NuGet; I've done that before. (I've realized that I did forget to bump the assembly version to 0.16.1, oops.) Could you try cloning the project and building the DLL yourself to double check that you're using the right version, please? In addition, you could try debugging with one of the test apps by changing the URL to point to your local test system's appcast files. Could you try that and let me know what happens, please?

Thanks.

christianerlinger commented 5 years ago

Hi,

sure thing, I'll try building a testcase using the example program and let you know the outcome.

I am on .NET 4.6.1 and running Visual Studio Community Edition 2017 if this is of any consequence btw.

cheers

Deadpikle commented 5 years ago

Please also let me know what your actual URL is (change words if you need to but not the overall format including dashes and the like) and relative path is, as it's possible your formatting is actually wrong and that's the problem 😅

I also updated NuGet to 0.16.2 'cause I found a Bad Bug. Might take a few minutes to propagate.

Let me know! We'll get to the bottom of it.

christianerlinger commented 5 years ago

Hi,

I upgraded to 1.16.2 - still get the same error.

I stripped the appcast.xml to the bare minimum:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
    <channel>
        <language>en</language>
        <item>
            <enclosure url="installer.exe"
                       sparkle:version="21.0.2"
                       type="application/octet-stream"/>
        </item>
    </channel>
</rss>

The appcast and the installer.exe are located in the very same folder.

The url would be

http://host-name:7777/somepath/some_alias_match/folder/appcast.xml

(the url structure including the - and _ are the very same in my local installation)

http://host-name:7777/somepath/some_alias_match/folder/installer.exe is available; I can download it e.g. via chrome.

Basing on your GetAbsoluteUrl method I built a Sparkle-Less repcase:

Uri baseUri = new Uri("http://host-name:7777/somepath/some_alias_match/folder/appcast.xml");
Uri downloaUri = new Uri(baseUri, "installer.exe");
using (WebClient webClient = new WebClient())
{
  webClient.DownloadFile(downloaUri, "d:\\temp\\install.exe");
}

Which downloads the installer.exe to d:\temp, so this shoud be correct.

Next thing I'll put a testcase together using the NetSparkle example app and let you know the outcome.

cheers

Deadpikle commented 5 years ago

Okie dokie.

Based on the stack trace I wonder if the NetSparkle.dll your app is using has been updated. The stack trace should include a call to Netsparkle.Utilities, and it doesn't. You can check the properties of the DLL to verify the version # by right clicking it under References and choosing Properties.

christianerlinger commented 5 years ago

Interesting. I really seem to have an old version of the NetSparkle.dll. Even though I upgraded, and removed NetSparkle from the references twice the version I am getting in the references property is 0.15.0.0.

packages.config shows

<package id="NetSparkle.New" version="0.16.2" targetFramework="net461" />

in the .csproj I have

 <Reference Include="NetSparkle, Version=0.15.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\packages\NetSparkle.New.0.16.2\lib\net45\NetSparkle.dll</HintPath>
    </Reference>

Maybe this is some oddity from VS Community 2017?

I'll look more into it tomorrow.

Have a nice day!

cheers

Deadpikle commented 5 years ago

Hey.

You're not crazy. Something is wrong with the NuGet build script I use and the NetSparkle DLL is indeed 0.15.0.

I'm looking into it now. So sorry for the hassle!!

Deadpikle commented 5 years ago

OK, I found and fixed the bug. No clue when that happened. (I'm in a bit of a rush at the moment and can't do the research now.) Please try updating your NuGet to 0.16.3 and see how that goes. Many apologies for the confusion and hassle.

christianerlinger commented 5 years ago

Hi!

After an update to 0.16.3 it's working now with relative URLs \o/ ;-).

No worries it wasn't a hassle at all. Your library saves me a ton of work - so thanks for that.

Thank you very much for the quick fix!

best regards Christian

Deadpikle commented 5 years ago

Hi,

So glad to hear! I'll go ahead and close the issue. :)