I'm using following code to subscribe to a channel. It's working fine when I try it on a .NET Console App but when I try the same code in a .NET windows service App, then it doesn't work (doesn't hit delegate (Pubnub pnObj, PNStatus status)). Is there anything else I need to add when building a windows service?
private void SubscribeToPubNub()
{
PNConfiguration pnConfig = new PNConfiguration();
pnConfig.SubscribeKey = RmmConnection.pNubSub;
pnConfig.PublishKey = RmmConnection.pNubSubPub;
pnConfig.Uuid = ConfigManager.GetUUID();
Pubnub pubnub = new Pubnub(pnConfig);
SubscribeCallbackExt mySubscribeListener = new SubscribeCallbackExt(
delegate (Pubnub pnObj, PNMessageResult<object> message)
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(message));
},
delegate (Pubnub pnObj, PNPresenceEventResult presence)
{
if (presence != null)
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(presence));
}
},
delegate (Pubnub pnObj, PNStatus status)
{
if (status != null && status.StatusCode == 200 && status.Category == PNStatusCategory.PNConnectedCategory)
{
//connected
}
});
pubnub.AddListener(mySubscribeListener);
pubnub.Subscribe<string>()
.Channels(new string[] { "rmm_channel" })
//.Channels(new string[] { RmmConnection.pNubChannel })
.WithPresence()
.Execute();
}
We’re having a problem to access a value we stored previously in keychain in a previous version of our app. We have updated our Xamarin.iOS version from 11.6.14 to 12.2.1.15 and our XCode version from 9.4.1 to 10.1.
We are not able to access that value anymore after the update.
I have read there are some changes in the security settings, but I’m not able to find the specifics about that. Is there anybody that had that problem before or has lot of experience with keychain? Thanks for your help!
bool WriteGenericPasswordValueToSecureKeychain(string service, string account, string value)
{
if (service == null || account == null || value == null)
{
throw new ArgumentNullException("Both arguments need a value and cannot be null");
}
var query = new SecRecord(SecKind.GenericPassword)
{
Service = service,
Account = account
};
var newRecord = new SecRecord(SecKind.GenericPassword)
{
Service = service,
Account = account,
ValueData = NSData.FromString(value, NSStringEncoding.UTF8)
};
SecStatusCode error;
var match = SecKeyChain.QueryAsRecord(query, out error);
if (error == SecStatusCode.Success)
{
error = SecKeyChain.Update(match, newRecord);
}
else
{
error = SecKeyChain.Add(newRecord);
}
if (error != SecStatusCode.Success && error != SecStatusCode.DuplicateItem)
{
return false;
}
return true;
}
I have an app published in the Play and App store, now I am in the work of publishing a new version for the app to both Play (Android) and App stores (iOS). Now, I want all the users to update to the new version when they use the app and not allow them to continue using the older version of the app without updating to the newer version.
Can anyone suggest me on how to force the users to update the app to the latest version once it is released in Play and App stores?
I don't know whether it is professional way or not., but this is the idea which struck my mind.
Add a variable with that app's version in App.cs or Mainpage.cs and and API with the current version as response.
Now check with the app's version and current version and redirect to homepage / any other page.
var version = 1.0;
var currentversion = 2.0; /* from API */
if(version == currentversion)
{
Navigation.PushModalAsync(new HomePage());
}
else
{
Navigation.PushModalAsync(new UpdatePage());
}
We must stop the old versions in the Play and App store.
For the future to do not stop (if we have some host - we should have it :) ):
someway save the version in the server side
every time when needed check the current version: getPackageManager().getPackageInfo(getPackageName(), 0).versionCode with version from server and force to update if needed.
good luck
How I am doing it my app is, when app starting in MyActivity I have code below
private void CompareVersion()
{
double currentVersion = 0d;
double appStoreversion =Convert.ToDouble(CosntValues.PlayStoreValues);
bool IsUpdateRequired = false;
if (Context.PackageName != null)
{
PackageInfo info = Context.PackageManager.GetPackageInfo(Context.PackageName, PackageInfoFlags.Activities);
string currentVersionStrig = info.VersionName;
currentVersion = Convert.ToDouble(currentVersionStrig);
}
try
{
if (IsUpdateRequired == false)
{
if (CheckNetConnection.IsNetConnected())
{
using (var webClient = new System.Net.WebClient())
{
var task = new VersionChecker();
task.Execute();
if ((appStoreversion.ToString() != currentVersion.ToString() && (appStoreversion > currentVersion)))
{
IsUpdateRequired = true;
}
}
}
}
if (IsUpdateRequired)
{
Activity.RunOnUiThread(() =>
{
AlertDialog dialog = null;
var Alertdialog = new Android.App.AlertDialog.Builder(Context);
Alertdialog.SetTitle("Update Available");
Alertdialog.SetMessage($"A new version of [" + appStoreversion + "] is available. Please update to version [" + appStoreversion + "] now.");
Alertdialog.SetNegativeButton("Cancel", (sender, e) =>
{
if (dialog == null)
{
dialog = Alertdialog.Create();
}
dialog.Dismiss();
});
Alertdialog.SetPositiveButton("Update", async (sender, e) =>
{
string appPackage = string.Empty;
try
{
appPackage = Application.Context.PackageName;
await Utilities.Logout(this.Activity);
var ints = new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + appPackage));
ints.SetFlags(ActivityFlags.ClearTop);
ints.SetFlags(ActivityFlags.NoAnimation);
ints.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(ints);
//StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + "com.sisapp.in.sisapp")));
}
catch (ActivityNotFoundException)
{
var apppack = Application.Context.PackageName;
//Default to the the actual web page in case google play store app is not installed
//StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("https://play.google.com/store/apps/details?id=" + "com.app.in.app")));
await Utilities.Logout(this.Activity);
var ints = new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + appPackage));
ints.SetFlags(ActivityFlags.ClearTop);
ints.SetFlags(ActivityFlags.NoAnimation);
ints.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(ints);
}
//this kills the app
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
System.Environment.Exit(1);
});
if (dialog == null)
dialog = Alertdialog.Create();
dialog.Show();
});
}
}
catch (Exception ex)
{
var objLog = new LogService();
objLog.MobileLog(ex, SISConst.UserName);
}
}
Followed by two separate above used classes
public class VersionChecker : AsyncTask
{
protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] #params)
{
var val1 = Jsoup.Connect("https://play.google.com/store/apps/details?id=" + "com.app.in.app" + "&hl=en")
.Timeout(30000).UserAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6").Referrer("http://www.google.com")
.Get();
var val2 = val1.Select(".htlgb");
var val3 = val2.Get(7).ToString();
//here mobile app version is of 3 values like 2.1, 4.2 etc
var version = val3.Substring(val3.IndexOf(">") + 1, 3); //fetching only 3 values ex 1.1
CosntValues.PlayStoreValues = version;
return version;
}
}
public static class CosntValues
{
public static string PlayStoreValues { get; set; }
}
Disclaimer: Use your app package name & above code is statically supporting for 3 digit version like 1.1, 1.2 etc.
Hope it help you
With this plugin I found a good solution and works perfectly in production. I strongly recommend this plugin. With this solution you can even give the user the possibility to go to the store right from your app
For example:
var isLatest = await CrossLatestVersion.Current.IsUsingLatestVersion();
if (!isLatest) //If the user does not have the last version
{
var update = await DisplayAlert("New version available", "There is a new version of our app. Would you like to download it?", "Yes", "No");
if (update)
{
//Open the store
await CrossLatestVersion.Current.OpenAppInStore();
}
}
I am working on an ETL process that is part of a larger system.
This larger system includes a logging system using a REST API.
The ETL section is running under SSIS, developed in Visual Studio 2015 and deployed on SQL Server 2016.
The ETL is covered with integration tests including tests of logs being generated.
The REST API cannot be guaranteed to be running during these integration tests, and even if it is, the asynchronous nature makes testing log generation... awkward.
We could use a script component to handle the logging, but we have 30+ packages requiring logging (each a distinct operation, based on a data-point to be calculated from one database into the next, so that a team can work concurrently without having TFS merge butcher XML definitions as much as possible), so maintenance becomes a headache.
In order to get around this, I have written a custom component that will bundle up all the errors across a package execution (separated into Fatal, Error, Warning, Info, and Detail levels), add a source, and fire JSON off to the REST API. In the event that the REST API is not specified, the system will log locally instead (which for the integration tests, means that we have a synchronous and local log source to check).
The ComponentType is ComponentType.DestinationAdapter.
The component has two custom properties, one for the variable name of the logging url (defaults to $Project::LoggingURL), one for the source of the log (defaults to System::PackageName).
The component validates the custom properties to not be blank.
The component has a single connection, defaulting to a master database, used as a fallback.
The component validates that the connection is set.
The component has multiple (five) inputs and no outputs.
Each input is marked as having side-effects.
Each attached input is validated as having a single input column of type DT_WSTR.
Unattached inputs are fine (a package that cannot log any fatal errors will leave that input unattached).
If any Fatal or Error messages are detected, the component fails the package in the Post-Execute step (in order to detect as many issues as possible in a run, rather than only the first).
The build targets 32-bit, and .NET Framework 4.
On Post-Build, the dll is copied to the DTS/PipelineComponents folder, and the assembly is deregistered then reregistered in the GAC.
When executing a package through Visual Studio (right-click on the package, 'Execute Package'), the component behaves exactly as expected.
When the package is deployed to the local SQL Server 2016 instance on my machine and the integration tests are run, the validation claims that the outputs leading into my component are not used and should be removed, and the component does nothing (as if it was never there). There are no messages about the component whatsoever.
I would very much like to have the component run in SQL Server, otherwise it is completely useless.
This is the code (there is an associated UI, but the Design-Time behaviour is as expected):
[DtsPipelineComponent(
DisplayName = "Custom Logging Component",
ComponentType = ComponentType.DestinationAdapter,
IconResource = "DestinationIcon",
CurrentVersion = 1,
UITypeName = "ETLCustomDataFlowComponents.CustomLoggingComponentUI,ETLCustomDataFlowComponents,Version=1.0.0.0,Culture=neutral,PublicKeyToken=051a7fa35dda5a9f"
)]
public class HermesCustomLoggingComponent : PipelineComponent
{
public const string _SOURCE_PROPERTY = "Source Name";
public const string _LOG_PROPERTY = "Log URL";
public const string _MASTER_CONN_PROPERTY = "Master Connection";
public override void ProvideComponentProperties()
{
base.ProvideComponentProperties();
base.RemoveAllInputsOutputsAndCustomProperties();
var loggingPath = ComponentMetaData.CustomPropertyCollection.New();
loggingPath.Description = "The url to send json log messages to";
loggingPath.Name = _LOG_PROPERTY;
loggingPath.Value = string.Empty;
loggingPath.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;
var source = ComponentMetaData.CustomPropertyCollection.New();
source.Description = "The source to which the log is to be attributed";
source.Name = _SOURCE_PROPERTY;
source.Value = string.Empty;
var masterConn = ComponentMetaData.RuntimeConnectionCollection.New();
masterConn.Name = _MASTER_CONN_PROPERTY;
masterConn.Description = "The connection to log.Log as a backup when centralised logging fails";
foreach (var level in new[] { "Fatal", "Error", "Warning", "Info", "Debug" })
{
var input = ComponentMetaData.InputCollection.New();
input.Name = level;
input.HasSideEffects = true;
}
}
public override DTSValidationStatus Validate()
{
bool broken = false;
bool cancel;
foreach (IDTSInput100 input in ComponentMetaData.InputCollection)
{
if (input.IsAttached)
{
if (input.InputColumnCollection.Count != 1)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{input.Name} should have only a message input", "", 0, out cancel);
broken = true;
}
else
{
if (input.InputColumnCollection[0].DataType != DataType.DT_WSTR)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"Input to {input.Name} is not of type DT_WSTR", "", 0, out cancel);
broken = true;
}
}
}
else
{
input.InputColumnCollection.RemoveAll();
}
}
if (ComponentMetaData.CustomPropertyCollection[_SOURCE_PROPERTY].Value == string.Empty)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{_SOURCE_PROPERTY} parameter has not been set", "", 0, out cancel);
broken = true;
}
if (ComponentMetaData.CustomPropertyCollection[_LOG_PROPERTY].Value == string.Empty)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{_LOG_PROPERTY} parameter has not been set", "", 0, out cancel);
broken = true;
}
if (ComponentMetaData.RuntimeConnectionCollection[_MASTER_CONN_PROPERTY].ConnectionManager == null)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, $"{_MASTER_CONN_PROPERTY} has not been set", "", 0, out cancel);
broken = true;
}
if (broken)
{
return DTSValidationStatus.VS_ISBROKEN;
}
return base.Validate();
}
private readonly List<Dictionary<string, string>> _logMessages = new List<Dictionary<string, string>>();
private readonly Dictionary<int, IDTSInput100> _inputs = new Dictionary<int, IDTSInput100>();
private readonly Dictionary<string, int> _messageCounts = new Dictionary<string, int>();
private string _source = string.Empty;
private string _loggingPath = string.Empty;
private SqlConnection sqlConnection;
public override void AcquireConnections(object transaction)
{
if (ComponentMetaData.RuntimeConnectionCollection[_MASTER_CONN_PROPERTY].ConnectionManager != null)
{
ConnectionManager cm = DtsConvert.GetWrapper(ComponentMetaData.RuntimeConnectionCollection[_MASTER_CONN_PROPERTY].ConnectionManager);
ConnectionManagerAdoNet cmAdoNet = cm.InnerObject as ConnectionManagerAdoNet;
if (cmAdoNet == null) throw new Exception($"Connection Manager {cm.Name} is not ADO.NET");
sqlConnection = cmAdoNet.AcquireConnection(transaction) as SqlConnection;
if ((sqlConnection != null) && (sqlConnection.State != ConnectionState.Open)) sqlConnection.Open();
}
}
public override void ReleaseConnections()
{
if ((sqlConnection != null) && (sqlConnection.State != ConnectionState.Closed)) sqlConnection.Close();
}
public override void PreExecute()
{
var sourceVar = ComponentMetaData.CustomPropertyCollection[_SOURCE_PROPERTY].Value;
if (sourceVar != string.Empty)
{
IDTSVariables100 variables;
VariableDispenser.LockForRead(sourceVar);
VariableDispenser.GetVariables(out variables);
_source = variables[sourceVar].Value.ToString();
}
var loggingVar = ComponentMetaData.CustomPropertyCollection[_LOG_PROPERTY].Value;
if (loggingVar != string.Empty)
{
IDTSVariables100 variables;
VariableDispenser.LockForRead(loggingVar);
VariableDispenser.GetVariables(out variables);
_loggingPath = variables[loggingVar].Value.ToString();
}
foreach (IDTSInput100 input in ComponentMetaData.InputCollection)
{
_inputs[input.ID] = input;
_messageCounts[input.Name] = 0;
}
}
public override void ProcessInput(int inputID, PipelineBuffer buffer)
{
while (buffer.NextRow())
{
string message = buffer[0].ToString();
_messageCounts[_inputs[inputID].Name] += 1;
_logMessages.Add(new Dictionary<string, string>
{
{"Level", _inputs[inputID].Name},
{"InstanceId", Environment.MachineName},
{"Source", _source},
{"Message", message}
});
}
}
public override void PostExecute()
{
if (string.IsNullOrWhiteSpace(_loggingPath))
{
List<string> logMessagesList = new List<string>();
foreach (var logMessage in _logMessages)
{
logMessagesList.Add(
$"('{logMessage["Level"].Substring(0, 1)}', '{logMessage["Source"]}', '{logMessage["Message"]}')");
}
if ((sqlConnection != null) && (sqlConnection.State == ConnectionState.Open))
{
var command = sqlConnection.CreateCommand();
command.CommandText =
$"INSERT INTO log.Log ([Level], [Source], [Message]) VALUES {string.Join(", ", logMessagesList)}";
command.ExecuteNonQuery();
}
}
else
{
List<string> logMessagesList = new List<string>();
foreach (var logMessage in _logMessages)
{
List<string> logJsonList = new List<string>();
foreach (var logElement in logMessage)
{
logJsonList.Add($"\"{logElement.Key}\":\"{logElement.Value}\"");
}
var logString = string.Join(", ", logJsonList);
if (!logMessagesList.Contains(logString))
{
logMessagesList.Add(logString);
}
}
string logJson = "[{" + string.Join("}, {", logMessagesList) + "}]";
var request = (HttpWebRequest)WebRequest.Create(_loggingPath + "api/log");
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = logJson.Length;
using (var requestWriter = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII))
{
requestWriter.Write(logJson);
}
}
foreach (var level in new[] { "Fatal", "Error" })
{
if (_messageCounts[level] > 0)
{
bool cancel;
ComponentMetaData.FireError(0, _source, "Package has logged an exception, and cannot continue", "",
0,
out cancel);
}
}
}
public override void PerformUpgrade(int pipelineVersion)
{
ComponentMetaData.Version = 1;
}
}
I am new to WebSockets (this AM) and have set up a WCF WebSocket app that works when doing a trivial example I found online (http://www.codeproject.com/Articles/619343/Using-WebSocket-in-NET-Part).
I added Entity Framework and as soon as I add code to try to access data the process (just sending a message back and forth) no longer works.
Could there be some fundamental concept I could be missing?
Does anyone have any good ideas for troubleshooting?
namespace PBWebSocket
{
public class PBWebSocket : IBWebSocket
{
private SPEntities db = new SPEntities();
public async Task SendMessageToServer(Message msg)
{
var callback = OperationContext.Current.GetCallbackChannel<IPBCallback>();
if (msg.IsEmpty || ((IChannel)callback).State != CommunicationState.Opened)
{
return;
}
byte[] body = msg.GetBody<byte[]>();
string msgTextFromClient = Encoding.UTF8.GetString(body);
var reqId = Int32.Parse(msgTextFromClient);
// *** The below line breaks it ***
var req = db.Requests.Where(r => r.Id == 164).FirstOrDefault();
reqId = reqId + 2;
Message newMsg = ByteStreamMessage.CreateMessage(
new ArraySegment<byte>(Encoding.UTF8.GetBytes(reqId.ToString())));
newMsg.Properties["WebSocketMessageProperty"] =
new WebSocketMessageProperty
{ MessageType = WebSocketMessageType.Text };
await callback.SendMessageToClient(newMsg);
}
}
}