HTML Not Rendering Data From Get Request - angular - c#

I'm working on chat application with c# as a server and angular as a client. I'm using SignalR for chatting between clients. My app is working well but I'm having trouble with getting a list of all connected users.
I know for sure that the client is reaching the server with http get request (after connecting to SignalR) because I console.log the connected users list and I'm getting the data:
The problem is that when I try to print the items of the list - it's not rendering and the fields are staying empty:
I expect seeing in the list myself (my details) and later on if I'm connecting to the app from Incognito to update the connected users list. But right now as you can see, I don't see my info.
I'm putting only the relevent parts of my code:
user component ts-
export class UsersComponent implements OnInit {
private signalrConnectionUrl='https://localhost:7014/userHub';
private addClientUrl='https://localhost:7014/Contacts/AddChatClient';
private sendMessageToAllUrl='https://localhost:7014/Contacts/SendMessageToAll';
chatClientId= getClientId();
chatMessage: string="";
userName=getUserName();
users: ConnectedClientModel[]=[];
constructor(public signalRService: SignalrService, private userService: UsersService, private http: HttpClient) { }
ngOnInit(): void {
this.startSignalrConnection();
};
startSignalrConnection(): void {
this.signalRService.startSignalrConnection(this.signalrConnectionUrl)
.then((signalrHubConnectionId) => {
firstValueFrom(this.http.post(this.addClientUrl,
buildNewChatClientConnectionModel(this.chatClientId, signalrHubConnectionId, this.userName!)))
.then((response) => {
this.signalRService.addListeners();
//getting all connected users
this.userService.getConnectedUsers().subscribe((users)=>{
this.users=users;
console.log(this.users);
})
console.log("Signalr started successfully with connectionId: " + signalrHubConnectionId + " And ready to get messages");
})
.catch((error) => {
console.log("Error while adding new chat client:", error);
alert("Error while adding new chat client:" + error);
console.log("chatClientId: " + this.chatClientId);
console.log("signalrHubConnectionId: " + signalrHubConnectionId);
});
})
.catch((error) => {
console.log("Error while establishing signalr connection:", error);
alert("Error while establishing signalr connection:" + error);
});
}
user component html (only the user list part)-
<h4 class="mb-3">List of Users</h4>
<div *ngFor="let user of users">
<div class="mb-2 mt-2">
<div><strong>Name</strong>{{user.Name}}</div>
<div><strong>Id</strong>{{user.ChatClientId}}</div>
<hr>
</div>
</div>
user service-
export class UsersService {
private getConnectedUsersUrl='https://localhost:7014/Contacts/GetConnectedUsers';
constructor(private http: HttpClient) { }
getConnectedUsers(): Observable<ConnectedClientModel[]> {
return this.http.get<ConnectedClientModel[]>(this.getConnectedUsersUrl);
}
}
ConnectedClientModel-
import { Guid } from "guid-typescript"
export interface ConnectedClientModel {
ChatClientId: Guid,
ConnectionId: string,
Name: string
}
Server get request-
[HttpGet("GetConnectedUsers")]
public async Task<IActionResult> GetConnectedUsers()
{
var allConnectedUsers = _signalrService.GetAllConnectedUsers();
return Ok(allConnectedUsers.Entity);
}

The properties coming from your backend start with a lowercase letter, yet in your Angular-model their first letter is capitalized. As a consequence the mapping might not be working anymore.
Can you once try to modify your model as follows?:
import { Guid } from "guid-typescript"
export interface ConnectedClientModel {
chatClientId: Guid,
connectionId: string,
name: string
}
And then also adapt the following two lines of your html:
<div><strong>Name</strong>{{user.name}}</div>
<div><strong>Id</strong>{{user.chatClientId}}</div>

Related

Stripe Redirect After Event

I'm using .NET and Stripe to make a webshop, and I'm trying to figure out how to redirect a customer to a success page, once the charge has been successfull. However Stripe recently changed their API, and I've been unable to find any resources online explaining how to do this.
I've tried creating a webhook that listens to the charge.succeeded event, and I can get the event to trigger, but I'm unable to redirect the customer to any page from the webhook.
Another thing I've tried is in the checkout page where I've added method="post" to the form, and type="submit" and formmethod="post" to the button respectively, so that when the customer clicks "Pay," the customer is redirected through the post method of the checkout page, but I can't get the post method to run.
Checkout razor page:
<head>
<title>Checkout</title>
<script src="https://js.stripe.com/v3/"></script>
</head>
<--! This is where I've tried method="post", type="submit" and formmethod="post" -->
<form id="payment-form">
<div id="card-element">
<!-- Elements will create input elements here -->
</div>
<!-- We'll put the error messages in this element -->
<div id="card-errors" role="alert"></div>
<button id="submit">Pay</button>
</form>
#section scripts{
<script>
// Set your publishable key: remember to change this to your live publishable key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
var stripe = Stripe('{PUBLIC KEY}');
var elements = stripe.elements();
window.onload = function () {
// Set up Stripe.js and Elements to use in checkout form
var style = {
base: {
color: "#32325d",
}
};
var card = elements.create("card", { style: style });
card.mount("#card-element");
card.addEventListener('change', function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
var form = document.getElementById('payment-form');
form.addEventListener('submit', function (ev) {
ev.preventDefault();
stripe.confirmCardPayment('#Model.ClientSecret', {
payment_method: {
card: card,
billing_details: {
name: '#Model.CustomerInformation.FirstName',
email: '#Model.CustomerInformation.Email',
address: {
city: '#Model.CustomerInformation.City',
line1: '#Model.CustomerInformation.Address1',
postal_code: '#Model.CustomerInformation.ZipCode'
}
}
}
}).then(function (result) {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
}
}
});
});
};
</script>
Webhook:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Stripe;
namespace workspace.Controllers
{
[Route("api/[controller]")]
public class StripeWebHook : Controller
{
// If you are testing your webhook locally with the Stripe CLI you
// can find the endpoint's secret by running `stripe listen`
// Otherwise, find your endpoint's secret in your webhook settings in the Developer Dashboard
const string endpointSecret = "ENDPOINT SECRET";
[HttpPost]
public async Task<IActionResult> Index()
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
try
{
var stripeEvent = EventUtility.ParseEvent(json);
// Handle the event
if (stripeEvent.Type == Events.PaymentIntentSucceeded)
{
var paymentIntent = stripeEvent.Data.Object as PaymentIntent;
Console.WriteLine("Successful!");
return Ok();
}
else if (stripeEvent.Type == Events.ChargeSucceeded)
{
Console.WriteLine("Successful!");
// This is where I've tried return RedirectToPage("/Index");
return Ok();
}
else if (stripeEvent.Type == Events.PaymentIntentCreated)
{
Console.WriteLine("Successful!");
return Ok();
}
else if (stripeEvent.Type == Events.PaymentMethodAttached)
{
var paymentMethod = stripeEvent.Data.Object as PaymentMethod;
Console.WriteLine("PaymentMethod was attached to a Customer!");
}
// ... handle other event types
else
{
// Unexpected event type
return BadRequest();
}
return Ok();
}
catch (StripeException e)
{
return BadRequest();
}
}
}
}
I think that we should iron out a few concepts here first. The webhook endpoint is a standalone API that lives in your system somewhere and reacts to Events that are posted to it from Stripe, such as the charge.succeeded Event.
Your Elements implementation in the browser is completely separate and can't respond to anything that your webhook endpoint can return in terms of HTTP codes (redirects and such).
To answer your core question directly, in the Javascript in the else block where it says that the payment was successfully processed, you can call [0]
location.href = "https://your-success-page.com"
... to send the user to a success page. The reason that the form won't submit is because the submit event of the form has been prevented with ev.preventDefault();.
This whole flow is documented in detail here [1][2].
Hope this helps!
[0] https://developer.mozilla.org/en-US/docs/Web/API/Window/location
[1] https://stripe.com/docs/payments/accept-a-payment
[2] https://stripe.com/docs/webhooks

SignalR in ReactJS page works just with reload

I use signalr in React.Js and have a problem that when I go to the pages by clicking the menu link and redirect with Route, it is not working. The back-end singleton class constructor is not called, but when I refresh a page or type the route manually in the address bar, it is works and connects to the back-end.
import $ from "jquery";
window.jQuery = $;
require("signalr");
{componentDidMount() {
var connection = $.hubConnection("http://localhost:1425/");
proxy = connection.createHubProxy("myHub");
connection
.start({ withCredentials: false })
.done(function () {
console.log("Now connected, connection ID=" + connection.id);
})
.fail(function () {
console.log("Could not connect");
});
}
Why does this happen and can anyone guide me on how should I fix that?

How to re-render a table after grabbing data from an API - React

I am using react-bootstrap-table to render a table. I grab information from an API and then I want the table to re-render. I am very new to react, and quite figure out where to set the state with the data so that my table will render properly after receiving the data. If I set the data directly in the render (not from the API), this renders actual information, so it's not the table setup.
Below is what I have so far. I've tried a few different places, so if it is completely wrong, please bear with me.
import React, { Component } from 'react';
import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
import 'react-bootstrap-table-next/dist/react-bootstrap-table2.min.css';
import $ from 'jquery';
class Table extends Component {
constructor(props) {
super(props);
//Controlled Component
this.state = {
poData: []
};
}
componentDidMount() {
var pos = [];
function myCallBack(data) {
// place your code here to do the work
var obj = JSON.parse(data);
// sample processing debug statements
var s = 'retrieved this data from suitelet: ';
console.log(s + data);
//alert(s + data);
return obj;
}
function getPOs() {
var obj2 = [];
alert("hi");
// name of the call back function that drives the JSONP mechanism; this string must be the same
// as your function that will ultimately process your request.
var cb = 'myCallBack'
//produce the JSON payload; JQuery will automatically add it to the URL for a JSONP call.
var data = { id: '24567', user: '23455' };
//note JQuery wants to see "callback=?" at the end of the URL; it tells the .getJSON call that this JSON request is of type JSONP
var url = 'https://myapi.com&callback=?';
//finally, the call. For convenience, we sent the data to our custom myCallBack function -- yet not mandatory in this implementation; the call back is in
// already referenced via the .done() method. Other JQuery capacities are can take care of failed calls
$.getJSON(url, data)
.done(function (data) {
obj2 = myCallBack(data);
})
return obj2;
}
var obj2 = getPOs();
this.setState({ poData: obj2 });
}
componentWillUnmount() {
this.setState({ poData: [] });
}
render() {
var poData = this.state.poData;
return (
<div>
<BootstrapTable data={poData} className="table" version='4'>
<TableHeaderColumn dataField='poID' isKey>PO ID</TableHeaderColumn>
<TableHeaderColumn dataField='poName'>PO Name</TableHeaderColumn>
<TableHeaderColumn dataField='poShipDate'>PO Ship Date</TableHeaderColumn>
</BootstrapTable>
</div>
);
}
}
export default Table;
EDIT:
Okay, I have cleaned it up some. I tried the componentDidMount stuff mentioned below, but my data never updates.
What I have below will now actually change the state properly, but it still never actually updates the table. Any ideas?
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Login from './Components/Login';
import Table from './Components/Table';
import $ from 'jquery';
class App extends Component {
constructor(props) {
super(props)
// the initial application state
this.state = {
isLoggedIn: false,
username: '',
password: '',
poData: []
};
}
componentDidMount() {
//TODO
}
signIn(username, password) {
// This is where you would call Firebase, an API etc...
// calling setState will re-render the entire app (efficiently!)
this.setState(
{
username: username,
password: password,
isLoggedIn: true,
poData: []
}
)
}
updateTable(poData) {
this.setState({
poData: poData
});
}
render() {
// Here we pass relevant state to our child components
// as props. Note that functions are passed using `bind` to
// make sure we keep our scope to App
return (
<div>
{
(this.state.isLoggedIn) ?
<div>
<Table data={this.state.poData} onUpdate={this.updateTable.bind(this)} />
</div>
:
<div>
<Login onSignIn={this.signIn.bind(this)} />
</div>
}
</div>
)
}
}
export default App;
and Table.js
import React, { Component } from 'react';
import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
import 'react-bootstrap-table-next/dist/react-bootstrap-table2.min.css';
import $ from 'jquery';
import App from '../App';
class Table extends Component {
constructor(props) {
super(props);
this.state = {
poData: []
};
this.getPOs = this.getPOs.bind(this);
}
getPOs() {
var url = 'https://myapi.com';
//CORS URL so that we can ignore the stupid CORS stuff
var proxyURL = 'https://cryptic-headland-94862.herokuapp.com/';
fetch(proxyURL + url).then(response => response.json().then(data => {
console.log(data);
console.log(data.length);
this.props.onUpdateTable(data);
}));
}
componentDidMount() {
//this.getPOs();
}
componentWillUnmount() {
//this.setState({ poData: [] });
}
render() {
this.getPOs();
return (
<div>
<BootstrapTable data={this.state.poData} className="table" version='4'>
<TableHeaderColumn dataField='poID' isKey>PO ID</TableHeaderColumn>
<TableHeaderColumn dataField='poName'>PO Name</TableHeaderColumn>
<TableHeaderColumn dataField='poShipDate'>PO Ship Date</TableHeaderColumn>
</BootstrapTable>
</div>
);
}
}
export default Table;
You should make the fetch request and store the result in state in ComponentDidMount(). You need to have a done() after your fetch, and then within that pass the data to state.

C# SignalR push notification real-time from Controller doesnt work

I've been trying to run several procedural code on server with parameter that i put on form and execute with MVC Controller. I want every step (method / function) on controller that have been called will update information to the client Web real-time.
I've been trying to use SignalR to update realtime push notification / information to client, its work with client trigger but when i trying to call hub from controller it doest work.
here is my Controller Code :
[HttpPost]
public string data (Models.ExModel data)
{
var hub = GlobalHost.ConnectionManager.GetHubContext<Hubs.MyHub1>();
//Execute Code
//send to client
hub.Clients.All.Message(data.apaAja);
return "success";
}
here is my client code :
<h2>Index</h2>
#Ajax.BeginForm("data", "Home", FormMethod.Post, null) {
<div class="input-group">
<span>Apa Aja</span>
#Html.EditorFor(model => model.apaAja, new { htmlhtmlAttributes = new { #id = "apaAja" } })
</div>
<div class="input-group">
<span> Boleh </span>
#Html.EditorFor(model => model.boleh, new { htmlhtmlAttributes = new { #id = "boleh" } })
</div>
<button id="subm" type="submit">Submit</button>
<div id="container">
</div>
#section scripts{
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
$(document).ready(function () {
var c = $.connection.myHub1;
c.client.messageSend = function (message) {
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#container').append('<li> < strong >' + 'Info Message : ' +
'</strong >: ' + encodedMsg + '</li >');
};
$.connection.hub.start();
});
</script>
and here is my Hub Class :
namespace SignalR1.Hubs
{
public class MyHub1 : Hub
{
public void Message(string message)
{
Clients.All.messageSend(message);
}
}
}
You have a client-side callback called messageSend, then in your hub you rightly have Clients.All.messageSend, however when you use the GlobalHost.ConnectionManager.GetHubContext you are accessing the hub context not the hub class itself.
So change it to:
var hub = GlobalHost.ConnectionManager.GetHubContext<Hubs.MyHub1>();
//you don't actually have access to the MyHub1 class at this point
// instead of
// hub.Clients.All.Message(data.apaAja);
// you need
hub.Clients.All.messageSend(data.apaAja);
In fact, the hub class method becomes slightly redundant when using this mechanism. I normally use the hub class for managing connections and clients using the overrides for onconnected etc...

Send a broadcast POP-UP Message to All the Connected Clients

I am building(still learning) a web application in ASP.NET WebForms with C#.We have a Centralized Database and all Clients are connected to the Database through a same static IP.Each of the Clients have their own
Unique Office ID.We have 16 Offices each having their own office ID.Every Day we update new features with new build.Instead of sending chat message
to individual client about the new changes/updates/features, can we make it send as a broadcast message like from all the offices i have mentioned
there is a corporate office with OfficeId=14.So the moment the User from other office Logs in, he/she should see a pop-up notification message
about the changes.Is it possible to make say a form to enter the details about the changes and the moment the user from the corporte office saves it, it shows in the index page of
all the clients?
I did a lot of research on this, but couldnt get a solid explanation.This might be a duplicate or lame question for all the experts out here,please
bear with me.
Check this link ASP.Net SignalR: Building a Simple Real-Time Chat Application
from the ChatHub class and Use following Code.
public class ChatHub : Hub
{
static ConcurrentDictionary<string, string> dic = new ConcurrentDictionary<string, string>();
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
public void Notify(string name, string id)
{
if (dic.ContainsKey(name))
{
Clients.Caller.differentName();
}
else
{
dic.TryAdd(name, id);
foreach (KeyValuePair<String, String> entry in dic)
{
Clients.Caller.online(entry.Key);
}
Clients.Others.enters(name);
}
}
public override Task OnDisconnected()
{
var name = dic.FirstOrDefault(x => x.Value == Context.ConnectionId.ToString());
string s;
dic.TryRemove(name.Key, out s);
return Clients.All.disconnected(name.Key);
}
}
And in HTML + javascript
<script type="text/javascript">
$(function () {
showModalUserNickName();
});
function showModalUserNickName() {
$("#dialog").dialog({
modal: true,
buttons: {
Ok: function () {
$(this).dialog("close");
startChartHub();
}
}
});
}
function startChartHub() {
var chat = $.connection.chatHub;
// Get the user name.
$('#nickname').val($('#nick').val());
chat.client.differentName = function (name) {
showModalUserNickName();
return false;
// Prompts for different user name
$('#nickname').val($('#nick').val());
chat.server.notify($('#nickname').val(), $.connection.hub.id);
};
chat.client.online = function (name) {
// Update list of users
if (name == $('#nickname').val())
$('#onlineusers').append('<div class="border" style="color:green">You: ' + name + '</div>');
else {
$('#onlineusers').append('<div class="border">' + name + '</div>');
}
};
chat.client.enters = function (name) {
$('#chatlog').append('<div style="font-style:italic;"><i>' + name + ' joins the conversation</i></div>');
$('#onlineusers').append('<div class="border">' + name + '</div>');
};
// Create a function that the hub can call to broadcast chat messages.
chat.client.broadcastMessage = function (name, message) {
//Interpret smileys
message = message.replace(":)", "<img src=\"/images/smile.gif\" class=\"smileys\" />");
message = message.replace("lol", "<img src=\"/images/laugh.gif\" class=\"smileys\" />");
message = message.replace(":o", "<img src=\"/images/cool.gif\" class=\"smileys\" />");
//display the message
$('#chatlog').append('<div class="border"><span style="color:red">' + name + '</span>: ' + message + '</div>');
};
chat.client.disconnected = function (name) {
//Calls when someone leaves the page
$('#chatlog').append('<div style="font-style:italic;"><i>' + name + ' leaves the conversation</i></div>');
$('#onlineusers div').remove(":contains('" + name + "')");
}
// Start the connection.
$.connection.hub.start().done(function () {
//Calls the notify method of the server
chat.server.notify($('#nickname').val(), $.connection.hub.id);
$('#btnsend').click(function () {
// Call the Send method on the hub.
chat.server.send($('#nickname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
}
</script>
<div id="container">
<input type="hidden" id="nickname" />
<div id="chatlog"></div>
<div id="onlineusers">
<b>Online Users</b>
</div>
<div id="chatarea">
<div class="messagelog">
<textarea spellcheck="true" id="message" class="messagebox"></textarea>
</div>
<div class="actionpane">
<input type="button" id="btnsend" value="Send" />
</div>
<div class="actionpane">
</div>
</div>
<div id="dialog" title="Enter your name to start a chat.">
<input type="text" id="nick" />
</div>

Categories

Resources