Serial communication(Serial UART) in raspberry-pi with windows 10 iot core and sim 900a - raspberry-pi

We were building and an app that could send and receive sms from sim900a module interfacing with raspberry-pi with windows 10 iot core.
In windows form application:-
We are going to read the serial data by making a call to ReadExisting method of SerialPort instance; which returns a partial response, so we have to loop through and append the data until the serial data that we received contain a substring “OK” or “\r\n>” means we have completely read the AT command response.
do
{
if (receiveNow.WaitOne(timeout, false))
{
string data = port.ReadExisting();
serialPortData += data;
}
}while (!serialPortData.EndsWith("\r\nOK\r\n") &&
!serialPortData.EndsWith("\r\n> ") &&
!serialPortData.EndsWith("\r\nERROR\r\n"));
How to do the same thing in universal windows platform(uwp)
I have used these commands but it reads partially(till \r \n), remaining part is not being read.
Task<UInt32> loadAsyncTask;
uint ReadBufferLength = 1024;
// Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available
dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
// Create a task object to wait for data on the serialPort.InputStream
loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask();
// Launch the task and wait
UInt32 bytesRead = await loadAsyncTask;
if (bytesRead > 0)
{
rcvdText.Text = dataReaderObject.ReadString(bytesRead);
status.Text = "bytes read successfully!";
}

Have a look at SerialDevice class. It can be created from USB vendorID/productID or by name (e.g. COM1). It provides stream based access to the serial port.
I´m not experienced with it (work in progress) but it seems like its the way to go for UWP.
This is my current attempt to serial communication in UWP (still untested!):
using SerialCommunication.Contracts.DataTypes;
using SerialCommunication.Contracts.Interfaces;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;
namespace SerialCommunication
{
public class SerialPort : ISerialPort, IDisposable
{
public SerialPort(string portName)
{
PortName = portName;
AdvancedQuery = SerialDevice.GetDeviceSelector(portName);
}
public SerialPort(ushort vendorId, ushort productId)
{
PortName = $"{nameof(vendorId)}={vendorId} {nameof(productId)}={productId}";
AdvancedQuery = SerialDevice.GetDeviceSelectorFromUsbVidPid(vendorId, productId);
}
public void Dispose() => Disconnect();
public string PortName { get; }
public string AdvancedQuery { get; }
public bool IsConnected => serialPort != null;
public int WriteTimeoutMilliseconds { get; set; }
public int ReadTimeoutMilliseconds { get; set; }
public uint BaudRate { get; set; }
public SerialParity Parity { get; set; } = SerialParity.None;
public SerialStopBitCount StopBits { get; set; } = SerialStopBitCount.One;
public ushort DataBits { get; set; } = 8;
public SerialHandshake Handshake { get; set; } = SerialHandshake.None;
public InputStreamOptions InputStreamOptions { get; set; } = InputStreamOptions.ReadAhead;
public UnicodeEncoding Encoding { get; set; } = UnicodeEncoding.Utf8;
public ByteOrder ByteOrder { get; set; } = ByteOrder.LittleEndian;
public bool Connect()
{
lock (serialPortLock)
{
CreateSerialDevice().Wait();
// serial port
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(WriteTimeoutMilliseconds);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(ReadTimeoutMilliseconds);
serialPort.BaudRate = BaudRate;
serialPort.Parity = Parity;
serialPort.StopBits = StopBits;
serialPort.DataBits = DataBits;
serialPort.Handshake = Handshake;
// output stream
dataWriter = new DataWriter(serialPort.OutputStream);
dataWriter.UnicodeEncoding = Encoding;
dataWriter.ByteOrder = ByteOrder;
// input stream
dataReader = new DataReader(serialPort.InputStream);
dataReader.InputStreamOptions = InputStreamOptions;
dataReader.UnicodeEncoding = Encoding;
dataReader.ByteOrder = ByteOrder;
// start reader
ReadWorker();
return IsConnected;
}
}
public void Disconnect()
{
lock (serialPortLock)
{
if (serialPort == null) return;
continuousReadData = false;
serialPort?.Dispose();
serialPort = null;
}
}
private async Task CreateSerialDevice()
{
var foundDevices = await DeviceInformation.FindAllAsync(AdvancedQuery);
if (foundDevices.Count == 0) throw new SerialPortException($"No device found: {nameof(PortName)}={PortName} {nameof(AdvancedQuery)}={AdvancedQuery}");
var deviceId = foundDevices[0].Id;
serialPort = await SerialDevice.FromIdAsync(deviceId);
if (serialPort == null) throw new SerialPortException($"Error creating device: {nameof(PortName)}={PortName} {nameof(AdvancedQuery)}={AdvancedQuery} {nameof(deviceId)}={deviceId}");
}
public void Write(byte[] bytes, int index = 0, int count = -1)
{
if (count < 0) count = bytes.Length - index;
byte[] tmp = new byte[count];
Array.Copy(bytes, index, tmp, 0, count);
WriteBytes(tmp);
}
public void InjectAndDispatch(byte[] receivedBytes)
{
lock (listeners)
{
foreach (var listener in listeners)
if (listener.IsActive)
listener.AddBytes(receivedBytes);
}
}
private async void ReadWorker()
{
continuousReadData = true;
while (continuousReadData)
{
await dataReader.LoadAsync(1);
byte[] receivedBytes = new byte[dataReader.UnconsumedBufferLength];
dataReader.ReadBytes(receivedBytes);
lock (listeners)
foreach (var listener in listeners)
if (listener.IsActive)
listener.AddBytes(receivedBytes);
}
dataReader.Dispose();
}
private async void WriteBytes(params byte[] bytes)
{
dataWriter.WriteBytes(bytes);
await dataWriter.StoreAsync();
await dataWriter.FlushAsync();
}
private readonly object serialPortLock = new object();
private SerialDevice serialPort;
private DataWriter dataWriter;
private DataReader dataReader;
private volatile bool continuousReadData = true;
#region listeners
public IListener AddListener()
{
lock (listenersLock)
{
var listener = new Listener();
listeners.Add(listener);
return listener;
}
}
public void RemoveListener(IListener listener)
{
lock (listenersLock)
listeners.Remove(listener as IListenerInternal);
}
private readonly object listenersLock = new object();
private readonly List<IListenerInternal> listeners = new List<IListenerInternal>();
class Listener : IListenerInternal
{
private bool _IsActive;
public bool IsActive
{
get { return _IsActive; }
set
{
if (_IsActive != value)
{
_IsActive = value;
Clear();
}
}
}
public void AddBytes(byte[] bytes)
{
lock (receivedBytesLock)
receivedBytes.AddRange(bytes);
BytesReceived?.Invoke(this, EventArgs.Empty);
}
public event EventHandler BytesReceived;
public byte[] GetReceivedBytesAndClear()
{
lock (receivedBytesLock)
{
var bytes = receivedBytes.ToArray();
receivedBytes.Clear();
return bytes;
}
}
public byte[] GetReceivedBytes()
{
lock (receivedBytesLock)
return receivedBytes.ToArray();
}
public void Clear()
{
lock (receivedBytesLock)
receivedBytes.Clear();
}
public void Trim(int length)
{
lock (receivedBytesLock)
{
var count = receivedBytes.Count;
if (count > length)
receivedBytes.RemoveRange(0, count - length);
}
}
private readonly object receivedBytesLock = new object();
private readonly List<byte> receivedBytes = new List<byte>();
}
#endregion
}
}
Furthermore I had trouble using the System.IO.SerialPort (of .NET Framework) with strings (ReadExisting etc). It seems like sometimes the encoding makes it hard to create good results. I always use it with byte arrays - less trouble, more fun!

Related

How do you isolate a text string from in a chatbox/text field in Unity?

I am making a chatbot (well I'm attempting!) and I have set up wit.ai to handle the text-to-speech of the bot. My issue is that I am pulling all of the chat into the speaker on each update which is overloading the TTS, when I really only want the line of the Bot (Dave) to go through the speaker and update with each new line. How can I isolate only the bots lines? Would love some help with this!
public class SimpleCharacter : MonoBehaviour
{
public GameObject item;
public Scrollbar verticalScrollbar;
public ScrollRect scrollRect;
public TMP_Text chatText;
private Animator anim;
public TTSSpeaker _speaker;
// Start is called before the first frame update
void Start()
{
Debug.Log("Simple Character start 0 ");
anim = GetComponentInChildren<Animator>();
if (anim == null)
{
Debug.Log("Simple Character anim is null");
}
Debug.Log("Simple Character start 1");
}
public void Think (string text)
{
string chat = chatText.text;
chat = chat + "/n" + text;
chatText.text = text;
anim.SetTrigger("Think");
}
public void Talk(List<Choice> choices)
{
string chat = chatText.text;
chatText.text = "";
Debug.Log("////////////////////// : " + chat);
chat = chat + "/n" + choices[0].ToString();
Debug.Log("////////////////////// : " + chat);
chatText.text = chat;
chatText.text = choices[0].ToString();
anim.SetTrigger("Talk");
}
public void Talk (string text)
{
string chat = chatText.text;
chat = chat + "/n" + text;
chatText.text = chat;
chatText.text = text;
_speaker.Speak(chatText.text);
}
}
Daves's lines are being received from this character's script
namespace OpenAI_Unity
{
public class OAICharacter : OAICompletion
{
protected override StringBuilder GetDefaultInformation()
{
Debug.Log("GetDefaultInformation - OAICharacter");
var sb = base.GetDefaultInformation();
sb.Replace("[Subject]", this.characterName);
sb.Append($"\n\nHuman: Hi\n{characterName}: Hello\nHuman: ");
return sb;
}
public override string Description { get => $"The following is a conversation between a Human and {characterName}.\n"; set => throw new System.NotImplementedException(); }
public override string InjectStartText { get => "\n" + characterName + ":"; set => throw new System.NotImplementedException(); }
[SerializeField]
private string characterName = "Dave";
public override string InjectRestartText { get => "\nHuman: "; set => throw new System.NotImplementedException(); }
public override string[] StopSequences { get => new string[] { "\n", "Human:" }; set => throw new System.NotImplementedException(); }
public override int NumOutputs { get => 1; set => throw new NotImplementedException(); }
private void ThrowError (string value)
{
Debug.LogError($"Can not set OAICharacter variable to {value}! If you want to modify these please use an OAISimpleObject instead");
}
}
}
This is the controller script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using OpenAI_Unity;
using TMPro;
public class ChatController : MonoBehaviour
{
public OAICharacter _oaiCharacter;
public TMP_InputField questionInput;
// Start is called before the first frame update
void Start()
{
questionInput.onEndEdit.AddListener((string data) =>
{
if (!string.IsNullOrEmpty(data))
{
_oaiCharacter.AddToStory(data);
}
questionInput.text = "";
});
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
questionInput.Select();
questionInput.ActivateInputField();
}
}
}
And the completion
namespace OpenAI_Unity
{
/// <summary>
/// Used for objects that communicate with OpenAI Completion
/// Abstract itself, for a Generic and fully customizable Completion object use OAIGenericCompletion
/// </summary>
public abstract class OAICompletion : MonoBehaviour
{
public abstract string Description
{
get; set;
}
public abstract string InjectStartText
{
get; set;
}
public abstract string InjectRestartText
{
get; set;
}
public abstract string[] StopSequences
{
get; set;
}
public EngineEnum engine;
public enum EngineEnum
{
Ada,
Babbage,
Curie,
Davinci
}
public enum LogLevel
{
None,
Responses,
ResponsesAndMemory
}
public LogLevel logLevel;
public int Max_tokens = 16;
[Range(0, 1)]
public double Temperature = 0.1;
[Range(0, 1)]
public double Top_p = 1;
public abstract int NumOutputs {get;set;}
[Range(0, 1)]
public double PresencePenalty = 1;
[Range(0, 1)]
public double FrequencyPenalty = 1;
public int LogProbs = 1;
public StringEvent QuestionReceivedEvent;
public ChoicesEvent ResponseReceivedEvent;
public ChoiceEvent ResponseReceivedEvent1;
/// <summary>
/// This can be disabled when using multiple responses, since they should not be manually added to the entire memory
/// </summary>
[HideInInspector]
public bool autoAddResponseToMemory = true;
public StringBuilder memory ;
private void Start()
{
Debug.Log("OAI Completion start 0 ");
memory = GetDefaultInformation();
Debug.Log("Start - memory: " + memory);
Debug.Log("OAI Completion start 1 ");
}
public void Brainwash(bool resetToDefault = true)
{
memory = resetToDefault ? GetDefaultInformation() : new StringBuilder();
}
/// <summary>
/// D
/// </summary>
/// <returns></returns>
protected virtual StringBuilder GetDefaultInformation()
{
Debug.Log("GetDefaultInformation - OAICompletion");
StringBuilder sb = new StringBuilder();
sb.Append(Description);
foreach (OAIBehavior behavior in GetComponents<OAIBehavior>())
{
string behaviorText = behavior.GetAsText();
sb.Append(behaviorText);
sb.Append(" ");
}
return sb;
}
public async void AddToStory(string value)
{
//QuestionReceivedEvent?.Invoke(value);
//Character should remember what they said before, since every time we send a request it requires the full 'story' to OpenAI
memory.Append(value).Append(InjectStartText);
QuestionReceivedEvent?.Invoke(memory.ToString());
if (logLevel == LogLevel.ResponsesAndMemory)
{
Debug.Log(memory);
}
if (!OAIEngine.Instance)
{
Debug.LogError("No OAIEngine object found in scene. Make sure there's a GameObject with an OAIEngine Component in your scene");
return;
}
//We allow the engine to change per request (= per character and per statement)
OAIEngine.Instance.Api.UsingEngine = GetEngine(engine);
if (NumOutputs < 1)
{
Debug.LogWarning($"NumOutputs was set to {NumOutputs}. You should have at least 1 output!");
NumOutputs = 1;
} else if (autoAddResponseToMemory && NumOutputs > 1)
{
Debug.Log("Multiple or no outputs are requested while autoAddResponseToMemory is still true. You should set this to false and manually call 'AddResponseToMemory' after selecting your prefered response.");
}
Debug.Log("Stop Seq: " + StopSequences[0] + " _ " + StopSequences[1]);
var c = new CompletionRequest(memory.ToString(), Max_tokens, Temperature, Top_p, NumOutputs, PresencePenalty, FrequencyPenalty, LogProbs, StopSequences);
var results = await OAIEngine.Instance.Api.Completions.CreateCompletionsAsync(c);
//ResponseReceivedEvent?.Invoke(results.Completions);
//We make it easy by auto-adding responses to the memory
if (autoAddResponseToMemory)
{
var r = results.Completions[0].Text;
AddResponseToMemory(r);
if (logLevel == LogLevel.Responses || logLevel == LogLevel.ResponsesAndMemory)
{
Debug.Log(r);
}
}
}
public void AddResponseToMemory (string value)
{
memory.Append(value).Append(InjectRestartText);
ResponseReceivedEvent1?.Invoke(memory.ToString());
Debug.Log("Memory: " + memory);
}
private Engine GetEngine(EngineEnum e)
{
switch (e)
{
case EngineEnum.Ada:
return Engine.Ada;
case EngineEnum.Babbage:
return Engine.Babbage;
case EngineEnum.Curie:
return Engine.Curie;
case EngineEnum.Davinci:
return Engine.Davinci;
}
return Engine.Default;
}
}
}
You should work with the text string that is passed to the function instead of the entire chat text. Assuming that all spoken dialog starts with "Dave: " you can easily detect this substring in the text, remove it and pass it to your text to speech.
using System;
string botName = "Dave: ";
public void Talk(string text){
chatText.text += "\n" + text;
if(text.StartsWith(botName)){
string spokenText = text.Remove(0, botName.Length)
_speaker.Speak(spokenText);
}
}

Xamarin forms - Cannot get object from REST API to xaml page

I am developing an Xamarin.Forms app in VS 2019. My REST API is hosted on GoDaddy.
When I call the api I get back my json converted object fine in my viewmodel. But the object is null
from my xaml page. See this code:
public class NewOrderViewModel : BaseViewModel
{
public NewOrderDetails NewOrderDetails { get; set; }
public ICommand OkCommand { get; private set;}
public ICommand CancelCommand { get; private set; }
readonly IPageService _pageService;
public NewOrderViewModel(IPageService pageService, int custId)
{
_pageService = pageService;
OkCommand = new Command(NewOrder);
CancelCommand = new Command(CancelOrder);
NewOrderDetails = new NewOrderDetails();
LoadNewOrderDetails(custId);
}
private async void LoadNewOrderDetails(int custId)
{
using (var client = new HttpClient(new System.Net.Http.HttpClientHandler()))
{
var response = await client.GetStringAsync("http://api.lates.com.au/api/Customers/" + custId.ToString());
var customer = JsonConvert.DeserializeObject<Customer>(response);
await _pageService.DisplayAlert("Value", customer.CustomerName, "OK"); //This confirms the correct customer is returned.
NewOrderDetails.CustomerName = customer.CustomerName;
foreach (var cd in customer.CustomerDepartments)
{
NewOrderDetails.CustomerDepartments.Add(cd);
}
NewOrderDetails.OrderDate = DateTime.Today;
NewOrderDetails.DeliveryDate = DateTime.Today;
NewOrderDetails.CustomerId = custId;
}
}
private void NewOrder()
{
_pageService.PopAsync();
_pageService.PushModalAsync(new CustomerOrder());
}
private void CancelOrder()
{
_pageService.PopAsync();
}
}
public partial class NewOrder : ContentPage
{
public NewOrder()
{
InitializeComponent();
imgAddIcon.Source = FileImageSource.FromFile("AddDocument64By64.png");
}
protected override void OnAppearing()
{
BindingContext = new NewOrderViewModel(new PageService(), 1);
//If i put a break point here the NewOrderDetails property of NewOrderViewModel is null - WHY???
}
}
It seems to be something to do with asynchronous timing. Let me know if you need more info.
Malcolm
If i put a break point here the NewOrderDetails property of
NewOrderViewModel is null - WHY???
At that time your break point hit, the data in NewOrderDetails has not be set because the httpRequest is still requesting and you have to await the request finish to get the data from Api.
To solve your problem, you have to implement INotifyPropertyChanged in both NewOrderDetails and NewOrderViewModel to notify the View update value after you get the data from Api. I will give you some code snippets:
In NewOrderDetails :
public class NewOrderDetails : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public NewOrderDetails()
{
}
public string CustomerName
{
set
{
if (customerName != value)
{
customerName = value;
OnPropertyChanged("CustomerName");
}
}
get
{
return customerName;
}
}
string customerName { get; set; }
}
In NewOrderViewModel :
public class NewOrderViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public NewOrderDetails NewOrderDetaila
{
set
{
if (newOrderDetails != value)
{
newOrderDetails = value;
OnPropertyChanged("NewOrderDetaila");
}
}
get
{
return newOrderDetails;
}
}
NewOrderDetails newOrderDetails { get; set; }
public NewOrderViewModel( int custId)
{
NewOrderDetaila = new NewOrderDetails();
LoadNewOrderDetails(custId);
}
private async void LoadNewOrderDetails(int custId)
{
//...
NewOrderDetaila.CustomerName = "133";
//...
}
}
And in Xaml binding:
<Label Text="{Binding NewOrderDetaila.CustomerName}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
Try and let me know if it works for you.
One problem in your code is here:
using (var client = new HttpClient(new System.Net.Http.HttpClientHandler()))
{
var response = await client.GetStringAsync("http://api.lates.com.au/api/Customers/" + custId.ToString());
var customer = JsonConvert.DeserializeObject<Customer>(response);
await _pageService.DisplayAlert("Value", customer.CustomerName, "OK"); //This confirms the correct customer is returned.
NewOrderDetails.CustomerName = customer.CustomerName;
foreach (var cd in customer.CustomerDepartments)
{
NewOrderDetails.CustomerDepartments.Add(cd);
}
NewOrderDetails.OrderDate = DateTime.Today;
NewOrderDetails.DeliveryDate = DateTime.Today;
NewOrderDetails.CustomerId = custId;
}
HttpClient should be defined as static class, and reused during your application lifetime. Disposing and recreating HttpClient leads to socket errors. Your code is causing multiple requests. I suggest also move this method to Task, that returns the object.
Example method:
internal class SendData
{
private static HttpClient client = new HttpClient();
internal static async Task<string> MakeServerRequest(string url, string content)
{
try
{
var request = new StringContent(content, Encoding.UTF8, "application/json");
var result = await client.PostAsync(url, request);
var response = await result.Content.ReadAsStringAsync();
return response;
}
catch (Exception ex)
{
YOUR ADDITIONAL LOGIC HERE
return null;
}
}
}
This will return JSON string that you can serialize to object, and do whatever your app requires.

Xamarin.Forms MVVM How to load bindable Picker with data from async process in ViewModel?

In my ViewModel i want o load the Picker source RegionName data from an Azure Region table. I extract data from table in an async method but the Picker displays an empty List even after ObservableCollection or List has changed or crashes.
When using PropertyChanged on the ListRegion list itself the app crashes.
In my models:
public class Region
{
public string Id { get; set; }
public string RegionName { get; set; }
}
In my RegisterPage.xaml:
<Picker SelectedIndex="{Binding RegionsSelectedIndex, Mode=TwoWay}"
ItemsSource="{Binding Regions}"
Margin="0,15,0,0"
Title="Select a region">
</Picker>
in my RegisterPage.cs:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class RegisterPage : ContentPage
{
RegisterViewModel registerVM;
public RegisterPage ()
{
InitializeComponent ();
registerVM = new RegisterViewModel();
this.BindingContext = registerVM;
}
protected override void OnAppearing()
{
base.OnAppearing();
}
in my RegisterPageViewModel:
public class RegisterViewModel: INotifyPropertyChanged
{
ApiServices _apiServices = new ApiServices();
public RegisterViewModel()
{
initializePickerAsync();
}
async private void initializePickerAsync()
{
try
{
var regionsList = await App.MobileService.GetTable<Models.Region>().ToListAsync();
List<string> regionsStringList = new List<string>();
foreach (Models.Region reg in regionsList)
{
regionsStringList.Add(reg.RegionName);
}
Regions = regionsStringList;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
/*
private RegisterViewModel (ObservableCollection<Models.Region> regionData)
{
ObservableCollection<string> regionDataAsStringList = new ObservableCollection<string>();
foreach (Models.Region r in regionData)
{
regionDataAsStringList.Add(r.RegionName);
}
this.Regions = regionDataAsStringList;
}
async public static Task<RegisterViewModel> BuildViewModelAsync()
{
ObservableCollection<Models.Region> tmpRegionData = new ObservableCollection<Models.Region>(await App.MobileService.GetTable<Models.Region>().ToListAsync());
return new RegisterViewModel(tmpRegionData);
}
*/
int regionsSelectedIndex = 0;
public int RegionsSelectedIndex
{
get
{
return regionsSelectedIndex;
}
set
{
if (regionsSelectedIndex != value)
{
regionsSelectedIndex = value;
OnPropertyChanged(nameof(RegionsSelectedIndex));
if (regionsSelectedIndex >= 0)
{
Region = Regions[regionsSelectedIndex];
}
}
}
}
// public ObservableCollection<Region> Regions {get;set}
public List<string> Regions
{
get
{
return Regions;
}
set
{
if (Regions != value)
{
Regions = value;
OnPropertyChanged(nameof(Regions));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
you seem to be doing a lot of unnecessary creating and assigning of different lists of data. You should be able to create your ObservableCollection ONCE and then add your data to it, something like this
in your ViewModel
ObservableCollection<Region> Regions { get; set; }
public RegisterViewModel()
{
Regions = new ObservableCollection<Region>();
}
public async void GetData()
{
var regionsList = await App.MobileService.GetTable<Models.Region>().ToListAsync();
foreach (Models.Region reg in regionsList)
{
Regions.Add(reg);
}
}
in your page
protected async override void OnAppearing()
{
base.OnAppearing();
await registerVM.GetData();
}

Custom Listener in Service Fabric + How to access from client?

Actually I am trying to learn Service fabric and its custom listener part. For this I have created a sample Service Fabric Stateful service which does nothing but returning a number 10 here.
internal sealed class StatefulService1 : StatefulService, INumber
{
protected override IEnumerable<ServiceReplicaListener>
CreateServiceReplicaListeners()
{
return new[] { new ServiceReplicaListener(context => new
HttpCommunicationListener(context), "HttpListener") };
}
public int GetNumber()
{
return 10;
}
}
I have created a custom Listener for this as below:
class HttpCommunicationListener : ICommunicationListener
{
StatefulServiceContext serviceContext;
string publishAddress;
public HttpCommunicationListener(StatefulServiceContext
serviceContext)
{
this.serviceContext = serviceContext;
}
public void Abort()
{
throw new NotImplementedException();
}
public Task CloseAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
var codePackageContext =
this.serviceContext.CodePackageActivationContext;
EndpointResourceDescription desc =
codePackageContext.GetEndpoint("ServiceEndpoint");
var port = desc.Port;
var address = string.Format("http://Address:{0}/", port);
this.publishAddress = address.Replace("Address",
FabricRuntime.GetNodeContext().IPAddressOrFQDN);
return Task.FromResult(publishAddress);
}
}
On the client side, I am struggling to access the GetNumber method using my listener,
My Client Side Implementation:
class CustomCommunicationClient : ICommunicationClient
{
public CustomCommunicationClient(ResolvedServicePartition partition)
{
this.ResolvedServicePartition = partition;
// this.Endpoint = partition.GetEndpoint();
}
public ResolvedServicePartition ResolvedServicePartition { get; set; }
public string ListenerName { get; set; }
public ResolvedServiceEndpoint Endpoint { get; set; }
}
Client Factory impl:
class CustomCommunicationClientFactory : CommunicationClientFactoryBase<CustomCommunicationClient>
{
ResolvedServicePartition partition;
public CustomCommunicationClientFactory(ResolvedServicePartition partition)
{
this.partition = partition;
}
protected override void AbortClient(CustomCommunicationClient client)
{
}
protected override Task<CustomCommunicationClient> CreateClientAsync(string endpoint, CancellationToken cancellationToken)
{
return Task.FromResult(new CustomCommunicationClient(this.partition));
}
protected override bool ValidateClient(CustomCommunicationClient client)
{
return true;
}
protected override bool ValidateClient(string endpoint, CustomCommunicationClient client)
{
return true;
}
}
Main.cs
class Program
{
private static string ServiceName = "fabric:/CustomCommunication.StatefulService/StatefulService1";
static void Main(string[] args)
{
var servicePartition = GetServicePartitionAsync();
var clientFactory = new CustomCommunicationClientFactory(servicePartition.Result);
var partition = new ServicePartitionKey(1);
var myServicePartitionClient = new ServicePartitionClient<CustomCommunicationClient>(clientFactory,
new Uri(ServiceName), partition);
Console.WriteLine("Running request client...");
//var result =
// myServicePartitionClient.InvokeWithRetryAsync(client => client., CancellationToken.None).Result;
Console.ReadKey();
}
private static Task<ResolvedServicePartition> GetServicePartitionAsync()
{
ServicePartitionResolver resolver = ServicePartitionResolver.GetDefault();
Task<ResolvedServicePartition> partition = resolver.ResolveAsync(new Uri(ServiceName),
new ServicePartitionKey(1), CancellationToken.None);
return partition;
}
}
Can someone please guide me on how to do it? It would be great if someone provide me a code for this.

Signalr & WebSocketSharp in Unity3d

I've currently built a simple Signalr Hub which I'm pushing messages to from a Unity5 project. Given that SignalR2 client doesn't work with Unity5 I'm using websocketsharp in order to intercept the websocket frames. The messages are being pushed to the Hub successfully, but when I attempt to call a method on the client, I do not get the payload string, only the message identifier {"I": 0}
Looking through the SignalR documentation, it looks like this gets sent last, but I have no idea how I can get a hold it it. I'm sure its something simple, but for the life of me I can't figure it out.
UPDATE
Upon request, I've added the code for the project below...
SignalRClient.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Newtonsoft.Json;
using WebSocketSharp;
namespace Assets.Scripts
{
class SignalRClient
{
private WebSocket _ws;
private string _connectionToken;
private Dictionary<string, UnTypedActionContainer> _actionMap;
private readonly string _socketUrl = "http://localhost/";
private readonly string _socket = "ws://localhost/";
public SignalRClient()
{
_actionMap = new Dictionary<string, UnTypedActionContainer>();
var webRequest = (HttpWebRequest)WebRequest.Create(_socketUrl + "/signalr/negotiate?connectionData=%5B%7B%22name%22%3A%22myHub%22%7D%5D&clientProtocol=1.3");
var response = (HttpWebResponse)webRequest.GetResponse();
using (var sr = new StreamReader(response.GetResponseStream()))
{
var payload = sr.ReadToEnd();
UnityEngine.Debug.Log(payload);
_connectionToken = Uri.EscapeDataString(JsonConvert.DeserializeObject<NegotiateResponse>(payload).ConnectionToken);
//UnityEngine.Debug.Log(_connectionToken);
}
}
public void Open()
{
_ws = _ws == null
? new WebSocket(_socket + "signalr/connect?transport=webSockets&connectionToken=" + _connectionToken)
: new WebSocket(_socket + "signalr/reconnect?transport=webSockets&connectionToken=" + _connectionToken);
AttachAndConnect();
}
public void Close()
{
_ws.Close();
}
public void SendMessage(string name, string message)
{
//{"H":"chathub","M":"Send","A":["tester","hello"],"I":0}
var payload = new RollerBallWrapper()
{
H = "myhub",
M = "Send",
A = new[] { name, message },
I = 12
};
var wsPacket = JsonConvert.SerializeObject(payload);
_ws.Send(wsPacket);
}
private void AttachAndConnect()
{
_ws.OnClose += _ws_OnClose;
_ws.OnError += _ws_OnError;
_ws.OnMessage += _ws_OnMessage;
_ws.OnOpen += _ws_OnOpen;
_ws.Connect();
}
void _ws_OnOpen(object sender, EventArgs e)
{
UnityEngine.Debug.Log("Opened Connection");
}
//
// This seems to be retriving the last frame containing the Identifier
void _ws_OnMessage(object sender, MessageEventArgs e)
{
//UnityEngine.Debug.Log(e.Data); // Returns {"I":"0"} ????
}
void _ws_OnError(object sender, WebSocketSharp.ErrorEventArgs e)
{
UnityEngine.Debug.Log(e.Message);
}
void _ws_OnClose(object sender, CloseEventArgs e)
{
UnityEngine.Debug.Log(e.Reason + " Code: " + e.Code + " WasClean: " + e.WasClean);
}
public void On<T>(string method, Action<T> callback) where T : class
{
_actionMap.Add(method, new UnTypedActionContainer
{
Action = new Action<object>(x =>
{
callback(x as T);
}),
ActionType = typeof(T)
});
}
}
internal class UnTypedActionContainer
{
public Action<object> Action { get; set; }
public Type ActionType { get; set; }
}
class MessageWrapper
{
public string C { get; set; }
public RollerBallWrapper[] M { get; set; }
}
class RollerBallWrapper
{
public string H { get; set; }
public string M { get; set; }
public string[] A { get; set; }
public int I { get; set; }
}
}
MyHub.cs
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
public class MyHub : Hub
{
public void Send(string name, string message)
{
var myConn = Context.ConnectionId;
Clients.All.broadcastMessage("John", "Hello");
}
}
The problem is the websocket connection. I had the following:
new WebSocket(_socket + "signalr/connect?transport=webSockets&connectionToken=" + _connectionToken)
Which was missing 2 critical querystring parameters: connectionData and tid in addition to the connectionToken and transport. I wrongly assumed that these weren't needed.
I hope this helps anyone who didn't read the documentation like me :)