Top Shelf giving an error Sequence contains more than one element - topshelf

I am trying to host a console application as window service using top shelf here is the code :
RunConfiguration cfg = RunnerConfigurator.New(x =>
{
x.ConfigureService<Certegy>(s =>
{
s.Named("certegy");
s.HowToBuildService(name => new Certegy());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
if (string.IsNullOrEmpty(args[1]))
{
x.RunAsLocalSystem();
}
else
{
x.RunAs(args[1], args[2]);
}
x.SetDescription("Certegy host to get the messages from the queue");
x.SetDisplayName("Certegy Interface");
x.SetServiceName("Certegy Interface");
});
Runner.Host(cfg, args);
From command line i am running as :
ExeName install username password
I am getting an error {"Sequence contains more than one element"} in last line
Runner.Host(cfg, args);
Can someone please help ?

What version of Topshelf are you using?
The username and password via the command line has not been working in a while, if you grab the latest development code from Chris, who added this feature, at https://github.com/phatboyg/Topshelf/tree/develop I think it has been addressed, otherwise just set it in the code to read from an app.config for the time being.

Related

WinAppDriver not working with side loaded Universal Application

I am unable to load a side loaded Windows Universal application using WinAppDriver
I have verified my code works if I try to load the Windows Calculator application but I am unable to load my target application. I get an error message "The system cannot find the file specified". I used the Get-AppxPackage method in PowerShell to get the application information for my target application. The method returned the data structure below:
Name : AACE4B69.MazikAXCashier
Publisher : CN=XXXXXXXXXXX
Architecture : Neutral
ResourceId :
Version : 2.4.1.9
PackageFullName : AACE4B69.MazikAXCashier_2.4.1.9_neutral__gfhc11b3bvd9y
InstallLocation : C:\Program Files\WindowsApps\AACE4B69.MazikAXCashier_2.4.1.9_neutral__gfhc11b3bvd9y
IsFramework : False
PackageFamilyName : AACE4B69.MazikAXCashier_gfhc11b3bvd9y
PublisherId : gfhc11b3bvd9y
IsResourcePackage : False
IsBundle : False
IsDevelopmentMode : False
NonRemovable : False
Dependencies : {Microsoft.WinJS.2.0_1.0.9600.17018_neutral__8wekyb3d8bbwe}
IsPartiallyStaged : False
SignatureKind : Developer
Status : Ok
I have tried to load the application using the following fields in the AppID field:
Name
PackageFullName
PackageFamilyName
[TestFixture]
public class Tests
{
protected static WindowsDriver<WindowsElement> windowSession;
public const String AppID = "AACE4B69.MazikAXCashier_2.4.1.9_neutral__gfhc11b3bvd9y";
public const String driverURL = "http://127.0.0.1:4723";
[SetUp]
public void Setup()
{
if (windowSession == null)
{
// Configure the application connection and load data
AppiumOptions opt = new AppiumOptions();
opt.AddAdditionalCapability("app", AppID);
try
{
// Create the driver object
windowSession = new WindowsDriver<WindowsElement>(new Uri(driverURL), opt);
Assert.IsNotNull(windowSession);
}
catch (Exception e)
{
Console.WriteLine("Unable to open application with error: " + e.Message);
}
}
}
[Test]
public void Test1()
{
Assert.Pass();
}}
I would expect one of these names to be the required Application ID and result in the app loading. Instead I get the error message "The system cannot find the file specified".
This application is side loaded and I am wondering if there is something different about that. Any help or suggestions are appreciated.
OK, I figured out the trick. I needed to user the PackageFamilyName appended with a qualifier. In my case this came out to be
public const String AppID = "AACE4B69.MazikAXCashier_gfhc11b3bvd9y!App";
I got this value via a two step process. I used the Powershell Get-appxPackage Mazik to get the PackageFamilyName as I previously did. I then appended "!App" to this string to get the required value. I determined the "!App" string based on another Powershell script I found in an online article. I used the following script to determine what the appended ID value was:
(Get-AppxPackageManifest (Get-AppxPackage Mazik)).package.applications.application.id
This returned "App" and I constructed the final string as described above. It looks like the "!App" is the typical ending to the required AppID but I have to assume there are different values for different situations. Once I got the correct AppID value everything worked as expected and the side loaded application was not an issue
The application key is usually a little shorter I believe. Are you sure you didn't make a mistake while copying it over to your code? Please double check app IDs for errors.
I created a shortcut to the Clocks app and then right clicked it. The "Target type" and "Target" fields contain the exact application key that work.

Firefox Native Messaging runtime.LastError not giving any errors in case of no Native application installed on Connectnative

I am trying to check whether the Native app is installed or not , If it is not I have to prompt the user to download it from the webpage. For chrome I used to achieve by checking the error messages from runtime.LastError. However in case of Firefox it gives error only in console No such native application extension_name and not catching it in the runtime.LastError method.
Is there any way that we can identify whether corresponding Native app is installed or not ?
I am facing issue when Native app is not installed and browser.runtime.lastError is not giving any error.
Can you please suggest if there is any way in Firefox Webextension that we can catch such errors and identify it in code whether the corresponding Native app is installed or not on the user machine.
It will really helpful if someone can provide some info on this.
for e.g. :
startNativeApp: function(force){
// note that when the native app is opened and ready, it will call "_ABC_onAgentReady"
ABC.log('Starting native app.');
if (!ABC.appConnected) {
try {
ABC.nativeAppPort = browser.runtime.connectNative(_ABC_native_app_id);
ABC.nativeAppPort.onMessage.addListener(ABC.onNativeMessageReceived);
ABC.nativeAppPort.onDisconnect.addListener(ABC.onNativeAppDisconnected);
ABC.appInstalled = true;
ABC.appConnected = true;
} catch(e) {
ABC.log('Error starting native app: ' + e.message, 'ERR');
}
} else if (force === true) {
ABC.log('Native app is already running; attempting to stop and will restart in 750ms.');
ABC.stopNativeApp();
setTimeout(function() { ABC.startNativeApp(true); }, 750);
}
},
onNativeAppDisconnected: function(message) {
console.log("ABC LastError : "+browser.runtime.lastError);
console.log("ABC LastError : "+ABC.nativeAppPort.error);
console.log("ABC LastError : "+JSON.stringify(message));
ABC.appConnected = false;
ABC.nativeAppPort = null;
ABC.appInstalled = false;
if (browser.runtime.lastError && (browser.runtime.lastError.message.indexOf("No such native application") !== -1 )) {
ABC.appInstalled = false;
}
// cleanup: reset the sig data so that it is re-requested on the next scan
_ABC_sa_data = "";
_ABC_sigs = "";
if (browser.storage && browser.storage.local) {
browser.storage.local.set({ uid: _ABC_be_uid }, null);
}
ABC.log('Send message to page to stop.');
ABC.sendMessageToPage({ onNativeAppDisconnected: '' });
ABC.log('Native app disconnected.');
},
Issue here was that port.error was not giving any error response in Firefox versions less than 52 , Due to which I was facing problem in identifying whether native app is installed or not.
After discussion on Mozilla Community (https://discourse.mozilla-community.org/t/firefox-native-messaging-runtime-lasterror-not-giving-any-errors-in-case-of-no-native-application-installed-on-connectnative/12880/4) , we found that it is actually missed and a bug is already reported : https://bugzilla.mozilla.org/show_bug.cgi?id=12994116
which will be resolved in Firefox 52.
However , I need to support Firefox 50 also , so the alternate I am using is to call native application in starting to find out whether it is installed or not.
If I got back response than it is installed otherwise it is not.
However specific error messages will be available from Firefox52.
Right now at chrome 109 the following approaches won't work after connectNative:
chrome.runtime.lastError. The error is printed because it is visible in the log but right after the call it is undefined.
console.error = function (arg) {/**/}. Is not working to replace the default function.
port.name is "" in both cases (error or no error).
port.onDisconnect is not called if the application is missing.
The only solution left is to call a third checker:
const promise=chrome.runtime.sendNativeMessage("appname", { /*text: ""*/ });//,check_response
promise.then(check_response,check_error);
In Firefox there is no runtime.lastError.
The listener function you pass to runtime.Port.onDisconnect isn't passed the message, it's passed the port itself.
You then want port.error.
See the documentation for onDisconnect here https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/Port

Auto-updates to Electron

I'm looking to deploy an auto-update feature to an Electron installation that I have, however I am finding it difficult to find any resources on the web.
I've built a self contained application using Adobe Air before and it seemed to be a lot easier writing update code that effectively checked a url and automatically downloaded and installed the update across Windows and MAC OSX.
I am currently using the electron-boilerplate for ease of build.
I have a few questions:
How do I debug the auto update feature? Do I setup a local connection and test through that using a local Node server or can I use any web server?
In terms of signing the application I am only looking to run apps on MAC OSX and particularly Windows. Do I have to sign the applications in order to run auto-updates? (I managed to do this with Adobe Air using a local certificate.
Are there any good resources that detail how to implement the auto-update feature? As I'm having difficulty finding some good documentation on how to do this.
I am also new to Electron but I think there is no simple auto-update from electron-boilerplate (which I also use). Electron's auto-updater uses Squirrel.Windows installer which you also need to implement into your solution in order to use it.
I am currently trying to use this:
https://www.npmjs.com/package/electron-installer-squirrel-windows
And more info can be found here:
https://github.com/atom/electron/blob/master/docs/api/auto-updater.md
https://github.com/squirrel/squirrel.windows
EDIT: I just opened the project to try it for a while and it looks it works. Its pretty straightforward. These are pieces from my gulpfile.
In current configuration, I use electron-packager to create a package.
var packager = require('electron-packager')
var createPackage = function () {
var deferred = Q.defer();
packager({
//OPTIONS
}, function done(err, appPath) {
if (err) {
gulpUtil.log(err);
}
deferred.resolve();
});
return deferred.promise;
};
Then I create an installer with electron-installer-squirrel-windows.
var squirrelBuilder = require('electron-installer-squirrel-windows');
var createInstaller = function () {
var deferred = Q.defer();
squirrelBuilder({
// OPTIONS
}, function (err) {
if (err)
gulpUtil.log(err);
deferred.resolve();
});
return deferred.promise;
}
Also you need to add some code for the Squirrel to your electron background/main code. I used a template electron-squirrel-startup.
if(require('electron-squirrel-startup')) return;
The whole thing is described on the electron-installer-squirrel-windows npm documentation mentioned above. Looks like the bit of documentation is enough to make it start.
Now I am working on with electron branding through Squirrel and with creating appropriate gulp scripts for automation.
You could also use standard Electron's autoUpdater module on OS X and my simple port of it for Windows: https://www.npmjs.com/package/electron-windows-updater
I followed this tutorial and got it working with my electron app although it needs to be signed to work so you would need:
certificateFile: './path/to/cert.pfx'
In the task config.
and:
"build": {
"win": {
"certificateFile": "./path/to/cert.pfx",
"certificatePassword": "password"
}
},
In the package.json
Are there any good resources that detail how to implement the auto-update feature? As I'm having difficulty finding some good documentation on how to do this.
You don't have to implement it by yourself. You can use the provided autoUpdater by Electron and just set a feedUrl. You need a server that provides the update information compliant to the Squirrel protocol.
There are a couple of self-hosted ones (https://electronjs.org/docs/tutorial/updates#deploying-an-update-server) or a hosted service like https://www.update.rocks
Question 1:
I use Postman to validate that my auto-update server URLs return the response I am expecting. When I know that the URLs provide the expected results, I know I can use those URLs within the Electron's Auto Updater of my Application.
Example of testing Mac endpoint with Postman:
Request:
https://my-server.com/api/macupdates/checkforupdate.php?appversion=1.0.5&cpuarchitecture=x64
JSON Response when there is an update available:
{
"url": "https:/my-server.com/updates/darwin/x64/my-electron=app-x64-1.1.0.zip",
"name": "1.1.0",
"pub_date": "2021-07-03T15:17:12+00:00"
}
Question 2:
Yes, your Electron App must be code signed to use the auto-update feature on Mac. On Windows I'm not sure because my Windows Electron app is code signed and I did not try without it. Though it is recommended that you sign your app even if the auto-update could work without it (not only for security reasons but mainly because otherwise your users will get scary danger warnings from Windows when they install your app for the first time and they might just delete it right away).
Question 3:
For good documentation, you should start with the official Electron Auto Updater documentation, as of 2021-07-07 it is really good.
The hard part, is figuring out how to make things work for Mac. For Windows it's a matter of minutes and you are done. In fact...
For Windows auto-update, it is easy to setup - you just have to put the RELEASES and nupkg files on a server and then use that URL as the FeedURL within your Electron App's autoUpdater. So if your app's update files are located at https://my-server.com/updates/win32/x64/ - you would point the Electron Auto Updater to that URL, that's it.
For Mac auto-update, you need to manually specify the absolute URL of the latest Electron App .zip file to the Electron autoUpdater. So, in order to make the Mac autoUpdater work, you will need to have a way to get a JSON response in a very specific format. Sadly, you can't just put your Electron App's files on your server and expect it to work with Mac just like that. Instead, the autoUpdater needs a URL that will return the aforementioned JSON response. So to do that, you need to pass Electron's Auto Updater feedURL the URL that will be able to return this expected kind of JSON response.
The way you achieve this can be anything but I use PHP just because that's the server I already paid for.
So in summary, with Mac, even if your files are located at https://my-server.com/updates/darwin/x64/ - you will not provide that URL to Electron's Auto Updater FeedURL. Instead will provide another URL which returns the expected JSON response.
Here's an example of my main.js file for the Electron main process of my App:
// main.js (Electron main process)
function registerAutoUpdater() {
const appVersion = app.getVersion();
const os = require('os');
const cpuArchitecture = os.arch();
const domain = 'https://my-server.com';
const windowsURL = `${domain}/updates/win32/x64`;
const macURL = `${domain}/api/macupdates/checkforupdate.php?appversion=${appVersion}&cpuarchitecture=${cpuArchitecture}`;
//init the autoUpdater with proper update feed URL
const autoUpdateURL = `${isMac ? macURL : windowsURL}`;
autoUpdater.setFeedURL({url: autoUpdateURL});
log.info('Registered autoUpdateURL = ' + (isMac ? 'macURL' : 'windowsURL'));
//initial checkForUpdates
autoUpdater.checkForUpdates();
//Automatic 2-hours interval loop checkForUpdates
setInterval(() => {
autoUpdater.checkForUpdates();
}, 7200000);
}
And here's an example of the checkforupdate.php file that returns the expected JSON response back to the Electron Auto Updater:
<?php
//FD Electron App Mac auto update API endpoint.
// The way Squirrel.Mac works is by checking a given API endpoint to see if there is a new version.
// If there is no new version, the endpoint should return HTTP 204. If there is a new version,
// however, it will expect a HTTP 200 JSON-formatted response, containing a url to a .zip file:
// https://github.com/Squirrel/Squirrel.Mac#server-support
$clientAppVersion = $_GET["appversion"] ?? null;
if (!isValidVersionString($clientAppVersion)) {
http_response_code(204);
exit();
}
$clientCpuArchitecture = $_GET["cpuarchitecture"] ?? null;
$latestVersionInfo = getLatestVersionInfo($clientAppVersion, $clientCpuArchitecture);
if (!isset($latestVersionInfo["versionNumber"])) {
http_response_code(204);
exit();
}
// Real logic starts here when basics did not fail
$isUpdateVailable = isUpdateAvailable($clientAppVersion, $latestVersionInfo["versionNumber"]);
if ($isUpdateVailable) {
http_response_code(200);
header('Content-Type: application/json;charset=utf-8');
$jsonResponse = array(
"url" => $latestVersionInfo["directZipFileURL"],
"name" => $latestVersionInfo["versionNumber"],
"pub_date" => date('c', $latestVersionInfo["createdAtUnixTimeStamp"]),
);
echo json_encode($jsonResponse);
} else {
//no update: must respond with a status code of 204 No Content.
http_response_code(204);
}
exit();
// End of execution.
// Everything bellow here are function declarations.
function getLatestVersionInfo($clientAppVersion, $clientCpuArchitecture): array {
// override path if client requests an arm64 build
if ($clientCpuArchitecture === 'arm64') {
$directory = "../../updates/darwin/arm64/";
$baseUrl = "https://my-server.com/updates/darwin/arm64/";
} else if (!$clientCpuArchitecture || $clientCpuArchitecture === 'x64') {
$directory = "../../updates/darwin/";
$baseUrl = "https://my-server.com/updates/darwin/";
}
// default name with version 0.0.0 avoids failing
$latestVersionFileName = "Finance D - Tenue de livres-darwin-x64-0.0.0.zip";
$arrayOfFiles = scandir($directory);
foreach ($arrayOfFiles as $file) {
if (is_file($directory . $file)) {
$serverFileVersion = getVersionNumberFromFileName($file);
if (isVersionNumberGreater($serverFileVersion, $clientAppVersion)) {
$latestVersionFileName = $file;
}
}
}
return array(
"versionNumber" => getVersionNumberFromFileName($latestVersionFileName),
"directZipFileURL" => $baseUrl . rawurlencode($latestVersionFileName),
"createdAtUnixTimeStamp" => filemtime(realpath($directory . $latestVersionFileName))
);
}
function isUpdateAvailable($clientVersion, $serverVersion): bool {
return
isValidVersionString($clientVersion) &&
isValidVersionString($serverVersion) &&
isVersionNumberGreater($serverVersion, $clientVersion);
}
function getVersionNumberFromFileName($fileName) {
// extract the version number with regEx replacement
return preg_replace("/Finance D - Tenue de livres-darwin-(x64|arm64)-|\.zip/", "", $fileName);
}
function removeAllNonDigits($semanticVersionString) {
// use regex replacement to keep only numeric values in the semantic version string
return preg_replace("/\D+/", "", $semanticVersionString);
}
function isVersionNumberGreater($serverFileVersion, $clientFileVersion): bool {
// receives two semantic versions (1.0.4) and compares their numeric value (104)
// true when server version is greater than client version (105 > 104)
return removeAllNonDigits($serverFileVersion) > removeAllNonDigits($clientFileVersion);
}
function isValidVersionString($versionString) {
// true when matches semantic version numbering: 0.0.0
return preg_match("/\d\.\d\.\d/", $versionString);
}

404 error when using https with signalR

I am using signalR over https and I have seeming done everything off this site:
https://weblog.west-wind.com/posts/2013/Sep/23/Hosting-SignalR-under-SSLhttps
Yet, I am still getting a 404 error when I signalr is trying to connect.
https://localhost:9000//negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22logshub%22%7D%5D&_=1438785507850 404 (Not Found)
This is my OWIN startup program starting on https://*:9000
class Program
{
static void Main(string[] args)
{
string dbFile = "logDB.sqlite";
if (!File.Exists(dbFile))
{
SQLiteDataProviderCreator.Create();
SQLiteDataProviderCreator.CreateDataBase();
}
IDataProvider provider = new SQLiteDataProvider("Data Source=logdb.sqlite;Version=3;PRAGMA journal_mode=WAL;Pooling=True;Max Pool Size=100;");
LogsModule.Provider = provider;
using (WebApp.Start<Startup>("https://*:9000/"))
{
Console.WriteLine("Launched site on Port 9000");
Console.WriteLine("Press [enter] to quit...");
Console.ReadLine();
}
}
}
And here the javascript that is supposed to allow it to connect over https.
var hubUrl = "https://localhost:9000/signalr";
$.connection.hub.url = hubUrl;
$.connection.hub.logging = true;
I also created a cert using makecert and bound it to the endpoint 0.0.0.0:9000.
Had a similar issue where I had to run the program as administrator.
For anyone else that comes across this.
The hubUrl should normally be:
var hubUrl = "https://localhost:9000/signalr/hubs";
This is even shown in the link provided.
Also, needs to ensure that the hub script is loaded prior to this script:
<script src='https://localhost:9000/signalr/hubs'></script>

RestSharp - when a test runs for the first time, it fails. When I debug, it passes. what's going on?

Pretty basic test:
[TestClass]
public class ApiClientTest
{
private RestClient _client;
[TestInitialize()]
public virtual void TestInitialize()
{
_client = new RestClient("http://localhost:24144");
_client.CookieContainer = new System.Net.CookieContainer();
}
[TestMethod]
public void ApiClientTestCRUD()
{
// 1. Log out twice. Verify Unauthorized.
var response = LogOut();
response = LogOut();
Assert.AreEqual(response.StatusCode, HttpStatusCode.Unauthorized);
// Error here:
Result Message: Assert.AreEqual failed. Expected:<0>.
Actual:< Unauthorized >.
I get <0>, which isn't even something that my WebAPI returns.
I think the issue is with my use of RestSharp, because if I debug one time it passes, and then subsequent runs pass. Any clue what's going on?
To be clear - this occurs when I open up my solution and attempt to run the test for the first time. I can fix it by debugging once, watching it pass, and then running without debugging as much as I want. I can reproduce this by closing VS and opening up the solution again - and running the test without debugging first.
Here's the LogOut method in my WebAPI:
[Authorize]
public HttpResponseMessage LogOut()
{
try
{
if (User.Identity.IsAuthenticated)
{
WebSecurity.Logout();
return Request.CreateResponse(HttpStatusCode.OK, "logged out successfully.");
}
return Request.CreateResponse(HttpStatusCode.Conflict, "already done.");
}
catch (Exception e)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, e);
}
}
UPDATE:
I ended up running the tests with Trace.WriteLine:
// 1. Log out twice. Verify Unauthorized.
Trace.WriteLine("ENTERING FIRST LOGOUT");
var response = LogOut();
Trace.WriteLine("Content: " + response.Content);
Trace.WriteLine("ErrorMessage: " + response.ErrorMessage);
Trace.WriteLine("ResponseStatus: " + response.ResponseStatus);
Trace.WriteLine("StatusCode: " + response.StatusCode);
Trace.WriteLine("StatusDescription: " + response.StatusDescription);
response = LogOut();
Trace.WriteLine("COMPLETED LOGOUTS");
Assert.AreEqual(response.StatusCode, HttpStatusCode.Unauthorized);
And I found the following:
ENTERING FIRST LOGOUT
Content:
ErrorMessage: Unable to connect to the remote server
ResponseStatus: Error
StatusCode: 0
StatusDescription:
COMPLETED LOGOUTS
My solution has a test project with this RestSharp test, and a WebAPI project that's supposed to be accepting these requests. If I debug, the RestClient connects. If not, it times out. Any tips?
When debugging is not possible to solve the problem go to the old fashion way.
Add Trace.WriteLine (or even append text to a C:\temp.txt file).
Write some string before every return in the LogOut method, then try writing some more information (if it's the last return then write the Exception message, if it's the second return write the Identity information.
Hope this helps.
How are you hosting the server? I see this that you're using port 24144. Maybe in debug mode you're running the express IIS Web Server and that's the port, but in non-debug mode it's not?

Resources