Integrating SignalR with existing WebAPI endpoint - c#

I have a Web API endpoint that creates a record and emits a successful 201 Created when the record is created.
Is it possible send a notification to a standalone HTML/JS web page that the record is created as it gets created using SignalR?
How can I create this publisher in the Web API and how to subscribe to it from the standalone webpage?

Yes - it is possible so long as that browser has an active connection to the SignalR Hub.
You can use this code as a starting point. It assumes you have a SignalR Hub class named MessageHub. This broadcasts a message to all active SignalR clients.
[RoutePrefix("api/messaging")]
public class MessagingController : ApiController
{
[Route("")]
public void Post(Message message)
{
var notificationHub = GlobalHost.ConnectionManager.GetHubContext<MessageHub>();
if (notificationHub != null)
{
try
{
// create your record
notificationHub.Clients.All.creationSuccess(message);
}
catch (Exception ex)
{
// do a thing
}
}
}
}
creationSuccess is the name of the function on the client side (JavaScript) which will handle the notification inside of the browser to which you're referring. Here's more information regarding the details of that

Related

How to store DB payloads and send them back up via Telemetry when not directly associated?

I've been trying to find a way to record all DB calls made during a HttpGet/Post. I am already logging the last one in case an error occurs, but the problem is that now I need to record all of them. The logging implemented currently interacts with Azure insights fine, but if I were to record all calls and send them back, I would get both unassociated data and too much data. So I'm looking for a way to only record and send back associated calls. I was thinking of storing all the calls in a Dictionary<int id, List<string> Payloads>.
This is how I am currently sending the last payload to azure
public class ODataURLInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
if (requestTelemetry != null)
{
requestTelemetry.Properties.Add("Last OData URL", ODataURLCapturer.URLs);
}
}
}
So I guess the real question is how do I store and retrieve data when calls are only barely associated.
Azure application insights can provide dependency metric. You can add application insights sdk into your application and enable-Sql-Command-Text-Instrumentation for logging sql command.
Add configuration in startup.cs to enable sql command text when using asp.net core
public void ConfigureServices(IServiceCollection services)
{
// The following line enables Application Insights telemetry collection.
services.AddApplicationInsightsTelemetry();
services.ConfigureTelemetryModule<DependencyTrackingTelemetryModule>((module, o) => { module.EnableSqlCommandTextInstrumentation = true; });
services.AddControllersWithViews();
}

Microsoft Graph Error Responses - How to extract HTTP Status Code and Inner Error Code from JSON?

I'm currently testing the MS Graph .NET Core SDK Client in my .NET Core 3.1 app. Purpose is to provide my own local Web API user service that performs updates/changes/fetching of users from Azure B2C AD.
In my intended solution, I will have various HTTP Client micro-services that will call API commands to my user service SDK Client, as opposed to calling the Azure Graph API using REST directly.
In my user service app, I'm trying to keep things clean by using a repository/interface approach for the actual SDK commands that are sent off to Azure. This same user service app is then returning the data back to my local HTTP Clients using my own WEB API. Imagine this user service app as the man in the middle effect.
Image below to summarize the environment:
The purpose of this is to reduce the work when changes or additions are made to the features used with the Graph Service i.e provide some standardization in comms across my own local apps and to promote better separation of concerns. Also if MS make changes to the Graph API, then I'm only updating the user service app rather than making code changes across all my HTTP Client apps. Hope that makes sense.
Anyway, now to the point! reason for my questions:
(bear with me here, I'm new to REST and using Interfaces)
Any errors encountered between the Graph SDK Client and the Graph Service API in Azure will be logged within the my user service app i.e. the extensive json error details i will capture at the first opportunity, HOWEVER I simply don't need to pass this level of detail back to all my local calling HTTP Clients.
What I'm trying to achieve is a means of identifying/capturing any HTTP Status code errors that were encountered between the SDK Client and the Graph Service, along with perhaps some basic details of the error i.e a short description and only pass these lower level details back to my local HTTP Clients i.e, keep things clean.
I'm struggling with knowing how to do this in my code, especially given the fact that i'm using an interface at the same time is making it more complex. The MS docs does give info on the list of expected error codes to be had from using the graph service, but there is no examples that explains how to process this information in order to pass the relevant (but lighter version of the info) back to another source.
Example scenario:
Local HTTP Clients call [HttpGet] GetUserById to my user service Web API
My Web API then uses the Graph SDK Client to reach out to Azure B2C, fetch the data and return.
My WEB API should then inspect the info received, if a user if found then great, return the user to my calling HTTP Client.
IF the user was not found, or perhaps a bad request was made (missing attributes / wrong user id etc) then I need to inspect the HTTP Status error code received and pass this same error code back to my calling HTTP Client, at the same time, rather than passing back the extensive json error details received from Graph Service, I just to want pass back a more simplified message, such as user not found.
The logical approach for the simplified message would be to utilize the already baked in codes messages provided by the Graph Service:
Like below: The "code" attribute is enough to explain the situation to any calling HTTP Client, if I need to investigate further then I would inspect the logs:
{
"error": {
"code": "invalidRange",
"message": "Uploaded fragment overlaps with existing data.",
"innerError": {
"requestId": "request-id",
"date": "date-time"
}
}
}
I just cant work out how to extract the HTTP Status code received from the the calls to the Graph Service through the SDK, as well as being able to fetch a single attribute from the json error message in the body and then return this reduced/simplified info back to my own HTTP Clients in the correct and conform ant manner. My own project code so far is below:
My user service WEB API Controller:
[HttpGet("{id}")]
public async Task<IActionResult> GetUserById(string id)
{
try
{
var user = await _repository.GetUserByIdAsync(id);
}
catch(Exception ex)
{
// What am I catching here? how do I get the HTTP Status Code that
was received from the call to the Graph Service in the event of an error?
// How do i extract the code error key/value from the json received from Graph Service?
}
// Finally, how do I return this captured info to the HTTP Client?
// Ignore this part, not sufficient for my needs.
//if (user == null) return BadRequest();
//if (user != null) return Ok(user);
//else return NotFound();
}
My Interface:
namespace MicrosoftGraph_API.Repository
{
public interface IGraphClientRepo
{
public Task<List<User>> GetAllUsersAsync();
public Task<User> GetUserByIdAsync(string id);
}
}
My Graph SDK Client Class:
public class GraphSDKClientRepo : IGraphClientRepo
{
public readonly IUserServiceClient _IUserServiceClient;
public GraphSDKClientRepo(IUserServiceClient userServiceClient)
{
_IUserServiceClient = userServiceClient;
}
public async Task<User> GetUserByIdAsync(string id)
{
var graphClient = _IUserServiceClient.InitializeGraphClient();
// Get user by object ID
var result = await graphClient.Users[id]
.Request()
.Select(e => new
{
e.DisplayName,
e.Id,
e.Identities
})
.GetAsync();
return result;
}
}
If your call encounters an error, the SDK will throw a ServiceException. This class includes the property you're looking for:
/// <summary>
/// The HTTP status code from the response.
/// </summary>
public System.Net.HttpStatusCode StatusCode { get; }
So your call to Graph would look something like:
public async Task<User> GetUserByIdAsync(string id)
{
var graphClient = _IUserServiceClient.InitializeGraphClient();
// Get user by object ID
try
{
return await graphClient
.Users[id]
.Request()
.Select("id,displayName,identities")
.GetAsync();
}
catch (ServiceException)
{
throw;
}
}
And you're Controller code would look something like
[HttpGet("{id}")]
public async Task<IActionResult> GetUserById(string id)
{
try
{
return this.Ok(await _repository.GetUserByIdAsync(id));
}
catch (ServiceException ex)
{
return this.StatusCode(se.StatusCode);
}
}
If you need to handle exceptions differently by HTTP Status, you can do that as well
[HttpGet("{id}")]
public async Task<IActionResult> GetUserById(string id)
{
try
{
return this.Ok(await _repository.GetUserByIdAsync(id));
}
catch (ServiceException e) when(e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
//
// Do "Not Found" stuff
//
return this.StatusCode(e.StatusCode);
}
catch (ServiceException e) when(e.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
//
// Do "Bad Request" stuff
//
return this.StatusCode(e.StatusCode);
}
catch (ServiceException e)
{
return this.StatusCode(e.StatusCode);
}
}

How to connect Hub if Hub is in different project SignalR?

I'm working with SignalR project, in which I want to use Hub in WebApi project as well as Web project. So I've created one class library project and implemented Hub over there.
My project structure looks like:
-ChatHub
-Hub
-Webapi
-Website
Here is my Hub:
[HubName("chathub")]
public class ChatHub : Hub
{
public override Task OnConnected()
{
return base.OnConnected();
}
public override Task OnReconnected()
{
return base.OnReconnected();
}
}
When I calling Hub from my website it's working well.
<script src="~/signalr/hubs"></script>
var chatHub = $.connection.chathub;
Here is how I connect Hub from outside(Android):
mHubConnection = new HubConnection(http://{IpAddress}/ChatApp/);
mHubProxy = mHubConnection.createHubProxy(chathub);
API:
public IHttpActionResult LoginUser([FromBody]LoginModel model)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
//chatUser logic here
hubContext.Clients.Client(chatUser.ConnectionId).receiver(response);
}
But it gives me an error:
java.util.concurrent.ExecutionException:
microsoft.aspnet.signalr.client.transport.NegotiationException: There
was a problem in the negotiation with the server
10-13 18:15:54.074 18686-18686/com.chatapp.android W/System.err:
Caused by:
microsoft.aspnet.signalr.client.http.InvalidHttpStatusCodeException:
Invalid status code: 404
How can we connect Hub if my Hub is out side of API project?
I've gone through Sharing a SignalR hub between a WebApi and MVC project but didn't get the answer they were provided.
Are you calling mHubConnection.Start() after setting up the connection and the proxy to the hub? Also is the url being passed into the HubConnection constructor the correct location for the hub? Here are a couple of links that might be helpful, if you haven't already been through them: Access hub from .NET client, configure signalr url

Adding a custom constructor in a WCF service and access it on the client (asp.net or windows forms)

I need to pass a string as a parameter to the WCF service through a custom constructor.
public partial class ServiceXX : IServiceXX
{
private string test;
static ServiceXX()
{
}
public ServiceXX()
{
this.test= null;
}
public ServiceXX(string test)
{
this.test= test;
}
}
Wanted to be able to access this constructor with parameter via a service reference (proxy) in the client.
Asp.net example:
using (ServiceXXClient proxy = new ServiceXXClient("Teste"))
{
}
Any suggestion?
You simply cannot. The client has no interest in you Service code. It only cares about the endpoint (abc - address, binding, contract). Remember you're not calling code, you're sending a message over a wire (or between processes) that will be received and translated to use your code.
client - call service (via through code friendly proxy)
- create message
- serialise
- send
service - receive message
- validate/verify
- deserialise
- authenticate/authorise
- call friendly code with friendly content

How do I get the IP address of my Corba client from the sever

I have a c++ client publishing Corba messages to a c# server via omniOrb. I have registered a PortableInterceptor with the Orb at the server end and can intercept messages.
In debug I get a ServerRequestInfo message in the intercept and In debug watch window can see the all the way down to the RemoteEndPort with the IP of the client. A lot of these classes however have private members which I can't access in the code.
How do I do it?
Here is my code
// register the OrbInitialiser here in some code
omg.org.CORBA.OrbServices orb = omg.org.CORBA.OrbServices.GetSingleton();
orb.RegisterPortableInterceptorInitalizer( new LT.Quantifi.BrokerOrbInitialiser());
orb.CompleteInterceptorRegistration();
// register the Inteceptor in the OrbInitialiser here
public class BrokerOrbInitialiser : omg.org.PortableInterceptor.ORBInitializer
{
public void post_init(ORBInitInfo info)
{
BrokerRequestInterceptor serverRequests = new BrokerRequestInterceptor();
info.add_server_request_interceptor(serverRequests);
}
}
// Inteceptor catches messages here
Public class BrokerRequestInterceptor : omg.org.PortableInterceptor.ServerRequestInterceptor
{
.
.
public void receive_request_service_contexts(ServerRequestInfo ri)
{
Console.WriteLine("I catch messages here");
}
.
.
}
There is no standard way to get access to that information in CORBA. Some implementations do have a custom way to get some information, for example TAO has a transport current object you can get access to. At the moment the call has been received using IIOP you can narrow that to a IIOP Transport Current which than gives you that information. Looks you need an extension for the C# ORB to have a similar extension

Categories

Resources