Mirror TextMeshPro text doesn't synchronize on client - unity3d

I'm trying to get users to see each other's nicknames, but it doesn't work on client.
On server it works fine? but on client texts don't sync. TextMehPro is child of PlayerPrefab
On Client
enter image description here
On Server
enter image description here
This is my network manager
using Mirror;
using TMPro;
public class NetManager : NetworkManager
{
private UserController controller;
public TextMeshPro nickname;
public override void Start()
{
base.Start();
controller = UserController.Shared;
}
private void OnCreateCharacter(NetworkConnectionToClient conn, UserMessage message)
{
var go = Instantiate(playerPrefab);
var user = new User(message);
var tank = go.GetComponent<TankController>();
tank.thisNick.text = user.UserName;
NetworkServer.AddPlayerForConnection(conn, go);
tank.SetUser(user);
}
public override void OnStartServer()
{
base.OnStartServer();
NetworkServer.RegisterHandler<UserMessage>(OnCreateCharacter);
}
public override void OnClientConnect()
{
base.OnClientConnect();
ActivatePLayerSpawn();
}
private void ActivatePLayerSpawn()
{
var user = controller.User;
var message = new UserMessage(user);
NetworkClient.Send(message);
}
}
public struct UserMessage: NetworkMessage
{
public string Name;
public int Coins;
public int Id;
public UserMessage(User u)
{
Name = u.UserName;
Coins = u.Coins;
Id = u.Id;
}
}

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);
}
}

Sync player names in unity multi-player

I'm trying to sync all the player names on server and client side, I'm following this tutorial, but I've made some changes to the code.
InitiateMultiplayer.cs
using Unity.Netcode;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Text;
namespace Multiplayer
{
public class InitiateMultiplayer : MonoBehaviour
{
[Serializable]
public class ConnectionPayload
{
public string password;
public string playerName;
}
public struct PlayerData
{
public string PlayerName { get; private set; }
public PlayerData(string playerName)
{
PlayerName = playerName;
}
}
private static Dictionary<ulong, PlayerData> clientData;
// Start is called before the first frame update
void Start()
{
NetworkManager.Singleton.NetworkConfig.ConnectionApproval = true;
switch (Buttons.GameMode)
{
case "Host":
clientData = new Dictionary<ulong, PlayerData>();
clientData[NetworkManager.Singleton.LocalClientId] = new PlayerData(Buttons.PlayerName);
NetworkManager.Singleton.ConnectionApprovalCallback += ApprovalCheck;
NetworkManager.Singleton.StartHost();
break;
case "Client":
Debug.Log("Client Started");
var payload = JsonUtility.ToJson(new ConnectionPayload()
{
password = "",
playerName = Buttons.PlayerName,
});
byte[] payloadBytes = Encoding.ASCII.GetBytes(payload);
// Set password ready to send to the server to validate
NetworkManager.Singleton.NetworkConfig.ConnectionData = payloadBytes;
NetworkManager.Singleton.StartClient();
break;
default:
break;
}
}
public static PlayerData? GetPlayerData(ulong clientId)
{
if (clientData.TryGetValue(clientId, out PlayerData playerData))
{
return playerData;
}
return null;
}
private void ApprovalCheck(NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response)
{
Debug.Log("approving");
string payload = Encoding.ASCII.GetString(request.Payload);
var connectionPayload = JsonUtility.FromJson<ConnectionPayload>(payload);
response.Approved = true;
response.Position = Vector3.zero;
response.Rotation = Quaternion.identity;
if (response.Approved)
{
response.CreatePlayerObject = true;
Debug.Log("approved");
response.PlayerPrefabHash = null;
response.Pending = false;
if (!clientData.TryGetValue(request.ClientNetworkId, out PlayerData playerData)) {
Debug.Log("we dont got data");
clientData[request.ClientNetworkId] = new PlayerData(connectionPayload.playerName);
}
}
}
}
}
Player.cs
using Unity.Netcode;
using UnityEngine;
using TMPro;
using Unity.Collections;
namespace Multiplayer
{
public class Player : NetworkBehaviour
{
[SerializeField] private TMP_Text displayNameText;
[SerializeField] private Renderer playerBody3D;
private NetworkVariable<FixedString32Bytes> displayName = new NetworkVariable<FixedString32Bytes>();
public override void OnNetworkSpawn()
{
if (!IsServer) { return; }
Debug.Log("Sapwned");
InitiateMultiplayer.PlayerData? playerData = InitiateMultiplayer.GetPlayerData(OwnerClientId);
if (playerData.HasValue)
{
Debug.Log("data -"+playerData.Value.PlayerName);
displayName.Value = playerData.Value.PlayerName;
}
}
private void OnEnable()
{
displayName.OnValueChanged += HandleDisplayNameChanged;
}
private void OnDisable()
{
displayName.OnValueChanged -= HandleDisplayNameChanged;
}
private void HandleDisplayNameChanged(FixedString32Bytes oldDisplayName, FixedString32Bytes newDisplayName)
{
if (IsClient) Debug.Log("client");
Debug.Log("Change in value"+newDisplayName.ToString());
displayNameText.text = newDisplayName.ToString();
}
}
}
The issue I'm facing is that the names are getting synced only on the server side, on the client side the palyer names are the default text.

How to get my specific Item index on inventory when pickup items?

So I want to make some inventory system for my game, and I found some issue when collecting the item, what I want here matching the index Inventory_UI system exactly the same as currentIndex on the collected item, then display it on Inventory_UI system, let say I pickUp some item with the currentIndex = 1 so on Inventory_UI system index=1 too and so on. this happening when inventory description too so the id is same as itemIndex picked up.
so here the the script:
ItemManager( this for information of item ):
[System.Serializable]
public class theItems
{
public string Name;
public GameObject[] allCurrentPrefabs;
public int numberOfIndex;
public AudioClip[] allSound;
public string[] terjemahannya;
public string[] latinnya;
}
public class _ItemManager : MonoBehaviour
{
public static _ItemManager instance;
private void Awake()
{
instance = this;
}
public List<theItems> items;
[Header("SurahApa")]
public int Surah;
[Header("SoundStuff")]
public AudioSource aSource;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void PlaySurah(int surahnya, int ayatnya)
{
aSource.clip = items[surahnya].allSurahSound[ayatnya];
aSource.Play();
}
}
CollectibleItem ( this attach to each item )
public static _CollectibleAyat instance;
private void Awake()
{
instance = this;
}
public enum InteractionType
{
none, pickUp, Examine
}
public InteractionType interactType;
public int currentIndex;
public string terjemahannya;
public string latinnya;
public GameObject allCurrentPrefabs;
public UnityEvent customevent;
public void Reset()
{
GetComponent<Collider2D>().isTrigger = true;
}
public void interact()
{
switch (interactType)
{
//case InteractionType.none:
// Debug.Log("None");
// break;
case InteractionType.Examine:
_InteractSystem.instance.Examine(this);
Debug.Log("Examine");
break;
case InteractionType.pickUp:
// Add the object to the pickUpItems List
// Delete the Object
_InventorySystem.instance.PickUpItem(gameObject);
gameObject.SetActive(false);
Debug.Log("PickingUp");
break;
default:
Debug.Log("Null Item");
break;
}
//Invoke (Call) the custom Event(s)
customevent.Invoke();
}
This InventorySystem( when item pickup)
public static _InventorySystem instance;
private void Awake()
{
instance = this;
}
[Header("GeneralFields")]
public List<GameObject> items = new List<GameObject>();
public bool isOpen;
public int ayah;
[Header("UI Items Section")]
public GameObject UI_InventoryWindow;
public Image[] item_Images;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.I))
{
ToggleInventory();
}
}
public void ToggleInventory()
{
isOpen = !isOpen;
UI_InventoryWindow.SetActive(isOpen);
}
public void PickUpItem(GameObject item)
{
items.Add(item);
Update_UI();
}
public void Update_UI()
{
HideAll();
for (int i = 0; i < items.Count; i++)
{
item_Images[i].sprite = items[i].GetComponent<SpriteRenderer>().sprite;
item_Images[i].gameObject.SetActive(true);
}
}
public void HideAll()
{
foreach (var i in item_Images)
{
i.gameObject.SetActive(false);
}
}
//SampeSini
public void ShowDescription(int id)
{
}
public void HideDescription()
{
}
InteractSystem ( this is for interact and storing collectibleItem system)
public static _InteractSystem instance;
private void Awake()
{
instance = this;
}
public Transform detectionPoint;
public const float detectionRadius = .2f;
public LayerMask detectionLayer;
public GameObject detectedObject;
public GameObject examinePanel;
private void Update()
{
if (DetectedObject())
{
if (PickUpInput())
{
detectedObject.GetComponent<_CollectibleAyat>().interactType = _CollectibleAyat.InteractionType.pickUp;
detectedObject.GetComponent<_CollectibleAyat>().interact();
_UIManager.instance.BackToGameFromExamine();
}
if (ExamineInput())
{
detectedObject.GetComponent<_CollectibleAyat>().interactType = _CollectibleAyat.InteractionType.Examine;
detectedObject.GetComponent<_CollectibleAyat>().interact();
}
}
}
bool PickUpInput()
{
return CrossPlatformInputManager.GetButtonDown("Fire1");
}
bool ExamineInput()
{
return CrossPlatformInputManager.GetButtonDown("Fire2");
}
bool DetectedObject()
{
Collider2D obj = Physics2D.OverlapCircle(detectionPoint.position, detectionRadius, detectionLayer);
if (obj == null)
{
detectedObject = null;
return false;
}
else
{
detectedObject = obj.gameObject;
return true;
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.green;
Gizmos.DrawSphere(detectionPoint.position, detectionRadius);
}
public void Examine(_CollectibleAyat items)
{
examinePanel.SetActive(true);
items.terjemahannya = _QuranManager.instance.quran[_QuranManager.instance.Surah].terjemahannya[items.currentAyah].ToString();
items.latinnya = _QuranManager.instance.quran[_QuranManager.instance.Surah].latinnya[items.currentAyah].ToString();
items.allCurrentSurahPrefabs = _QuranManager.instance.quran[_QuranManager.instance.Surah].allCurrentSurahPrefabs[items.currentAyah];
var go = Instantiate(items.allCurrentSurahPrefabs, _UIManager.instance.instantiatePosition.position,Quaternion.identity);
go.transform.SetParent(_UIManager.instance.instantiatePosition.transform);
_UIManager.instance.terjemahanText.text = items.terjemahannya;
_UIManager.instance.latinText.text = items.latinnya;
}
Here is the Preview :
2.
note: on the ShowDescription(int id) i want to show item information that same as I picked up I have mentioned at first above.

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.

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.