ClickOnce 没有传递第二个 Uri

ClickOnce not passing second Uri

我们有一个 WPF 应用程序,它使用 WindowsFormsApplicationBase class 使其成为 singleton;并使用 ClickOne 进行部署。每当我们想要执行这个 exe 时,我们都会通过 Uri(服务器中带有查询字符串的部署目录)调用它。仅适用于此应用程序的第一个实例,一切正常。

问题:无论传递什么Uri,每次启动单实例应用程序时,ClickOnce总是传递第一个Uri。此外,StartupNextInstanceEventArgs 不会为同一应用程序的任何后续实例化填充。

有人遇到过这个问题吗?

提前致谢。

到目前为止,我的问题还没有得到任何具体的答案。因此,我决定实施一个不同的解决方案 here。不幸的是,原始问题在这两种方法中都适用。所以我决定在第二种方法之上做一个变通方法(参见 url)来解决这个问题,直到我有一个干净的解决方案。

解决方法

  1. 修改入口点(主要)以包含一项功能,该功能将传入的激活 uri 保存到应用程序配置文件。您必须保留保存该值的位置,因为它往往会在某处用旧的激活 uri 覆盖。记住这是我的问题。

     public static void Main()
     {
       string uri;
       StartupHelpers.SetConfigurationValue("ActivationUri", (StartupHelpers.HasTriggeredFromUrl(out uri)) ? uri : string.Empty);    
       if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
            {
             var application = new App();
             application.Run();
             SingleInstance<App>.Cleanup();
            }
     }
    
  2. 现在实现接口(ISingletonInstanceApp)如下。

        public bool SignalExternalCommandLineArgs(IList<string> args)
        {
            var uri = new  Uri(StartupHelpers.GetConfigurationValue("ActivationUri"));
            int queryString = 0;
            if (StartupHelpers.IsTriggeredFromWLink(uri, out queryString))
            {
            //in my case I have a function LoadPage which take 
            //some parameter to populate UI.   Your case might be
            //totally  different. However, the idea is on how we
            //could grab   running instance and pass value into
            // it to do something different.
    
                ((YourMainWindow) (Current.MainWindow)).LoadPage(queryString.ToString());
    
            }
    
            // Bring window to foreground
            if (this.MainWindow.WindowState == WindowState.Minimized)
                {
                this.MainWindow.WindowState = WindowState.Normal;
                }
    
            this.MainWindow.Activate();
    
            return true;
            }
    
  3. 帮助 get/set 配置值。

        public static class StartupHelpers
    {
          public static bool HasTriggeredFromUrl(out string uri)
           {
            try
            {
                uri = string.Empty;
                var activeUri = ApplicationDeployment.CurrentDeployment.ActivationUri;
                uri = activeUri != null ? activeUri.ToString() : string.Empty;
                return true;
            }
            catch (InvalidDeploymentException inv)
            {
                uri = string.Empty;
                return false;
            }
        }
    
        public static bool IsTriggeredFromLink(Uri activationUri, out int queryStringValue)
        {
            queryStringValue = 0;
            var hasTriggeredFromLink = true;
            if (string.IsNullOrWhiteSpace(activationUri.Query) ||
                HttpUtility.ParseQueryString(activationUri.Query).Count <= 0)
                hasTriggeredFromLink = false;
            else
            {
                if (!int.TryParse(HttpUtility.ParseQueryString(activationUri.Query)[0], out queryStringValue))
                    throw new Exception("Invalid startup argument found from web site.");
    
            }
    
            return hasTriggeredFromLink;
        }
    
        public static bool SetConfigurationValue(string key, string value)
        {
            try
            {
                Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                appConfig.AppSettings.Settings[key].Value = value;
                appConfig.Save(ConfigurationSaveMode.Full);
                ConfigurationManager.RefreshSection("appSettings");
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return true;
        }
    
        public static string GetConfigurationValue(string key)
        {
            try
            {
                Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                ConfigurationManager.RefreshSection("appSettings");
                return appConfig.AppSettings.Settings[key].Value;
    
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
    

有点迟到的答案,但我在研究将应用程序强制到单个实例时偶然发现了这个问题。

如果我明白你想做什么,你想要一个接受命令行参数的单实例应用程序。第二次尝试应用程序 运行,您只想保留第一个实例,但将第二组命令行参数传递给它。

在这种情况下,为什么不使用适当的方法在您的 WPF 应用程序中托管 WCF 服务,而是将这些参数传递给该方法。使用 ClickOnce 的网页随后只需使用它传递的参数调用此服务方法。