1656614160
This is a lightweight library that works as a connector to Binance public API
/api/*
/sapi/*
dotnet add package Binance.Spot
Usage example
using System;
using System.Threading.Tasks;
using Binance.Spot;
class Program
{
static async Task Main(string[] args)
{
Wallet wallet = new Wallet();
string status = await wallet.SystemStatus();
Console.WriteLine(status);
}
}
Please find more examples folder to check for more endpoints.
using System;
using System.Threading;
using System.Threading.Tasks;
using Binance.Spot;
class Program
{
static async Task Main(string[] args)
{
var websocket = new MarketDataWebSocket("btcusdt@aggTrade");
websocket.OnMessageReceived(
(data) =>
{
Console.WriteLine(data);
return Task.CompletedTask;
}, CancellationToken.None);
await websocket.ConnectAsync(CancellationToken.None);
}
}
More websocket examples are available in the Examples
folder
Once connected, the websocket server sends a ping frame every 3 minutes and requires a response pong frame back within a 10 minutes period. This package handles the pong responses automatically.
While /sapi/*
endpoints don't have testnet environment yet, /api/*
endpoints can be tested in Spot Testnet.
using Binance.Spot;
Wallet wallet = new Wallet(baseUrl: "https://testnet.binance.vision");
If baseUrl
is not provided, it defaults to https://api.binance.com
.
It's recommended to pass in the baseUrl
parameter, even in production as Binance provides alternative URLs in case of performance issues:
https://api1.binance.com
https://api2.binance.com
https://api3.binance.com
Additional parameter recvWindow
is available for endpoints requiring signature.
It defaults to 5000
(milliseconds) and can be any value lower than 60000
(milliseconds). Anything beyond the limit will result in an error response from Binance server.
using Binance.Spot;
Wallet wallet = new Wallet();
await wallet.AccountStatus(recvWindow=4000)
The default timeout is 100,000 milliseconds (100 seconds).
Usage Example
using System;
using System.Net.Http;
using Binance.Spot;
HttpClient httpClient = new HttpClient() {
Timeout = TimeSpan.FromSeconds(10)
}
Wallet wallet = new Wallet(httpClient: httpClient);
Usage Example
using System;
using System.Net;
using System.Net.Http;
using Binance.Spot;
WebProxy proxy = new WebProxy(new Uri("http://1.2.3.4:8080"));
HttpClientHandler proxyHandler = new HttpClientHandler { Proxy = proxy };
HttpClient httpClient = new HttpClient(handler: proxyHandler);
Wallet wallet = new Wallet(httpClient: httpClient);
There are 2 types of exceptions returned from the library:
Binance.Common.BinanceClientException
4XX
, it's an issue from client side.Code
- Server's error code, e.g. -1102
Message
- Server's error message, e.g. Unknown order sent.
Binance.Common.BinanceServerException
5XX
, it's an issue from server side.Both exceptions inherit Binance.Common.BinanceHttpException
along with the following properties:
StatusCode
- Response http status code, e.g. 401
Headers
- Dictionary with response headersThis library implements the .NET logging API that works with a variety of built-in and third-party logging providers.
For more information on how to configure logging in .NET, visit Microsoft's logging article
Usage Example
using System;
using System.Net;
using System.Net.Http;
using Binance.Spot;
public async Task LoggingExample(ILogger logger) {
BinanceLoggingHandler loggingHandler = new BinanceLoggingHandler(logger: logger);
HttpClient httpClient = new HttpClient(handler: loggingHandler);
Wallet wallet = new Wallet(httpClient: httpClient);
await wallet.SystemStatus();
}
Sample Output
Method: GET, RequestUri: 'https://www.binance.com/?timestamp=1631525776809&signature=f07558c98cb82bcb3556a6a21b8a8a2582bae93d0bb9604a0df72cae8c1c6642', Version: 1.1, Content: <null>, Headers: { }
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: <null>, Headers: {}
{"status": 0,"msg": "normal"}
dotnet test
Futures and Vanilla Options APIs are not supported:
Contributions are welcome.
If you've found a bug within this project, please open an issue to discuss what you would like to change.
If it's an issue with the API, please open a topic at Binance Developer Community
Download Details:
Author: binance
Source Code: https://github.com/binance/binance-connector-dotnet
License: MIT license
#Binance #blockchain #dotnet #csharp
1656543360
rich set of enterprise-class UI components based on Ant Design and Blazor.
WebAssembly static hosting examples:
![]() Edge / IE | ![]() Firefox | ![]() Chrome | ![]() Safari | ![]() Opera | ![]() Electron |
---|---|---|---|---|---|
Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 |
Due to WebAssembly restriction, Blazor WebAssembly doesn't support IE browser, but Blazor Server supports IE 11† with additional polyfills. See official documentation.
From .NET 5, IE 11 is no longer officially supported. See Blazor: Updated browser support. Unofficial support is provided by Blazor.Polyfill community project.
Regularly synchronize with Official Ant Design specifications, you can check the sync logs online.
Therefore, you can use the custom theme styles of Ant Design directly.
We have provided the dotnet new
template to create a Boilerplate project out of the box:
Install the template
$ dotnet new --install AntDesign.Templates
Create the Boilerplate project with the template
$ dotnet new antdesign -o MyAntDesignApp
Options for the template:
Options | Description | Type | Default |
---|---|---|---|
-f | --full | If specified, generates all pages of Ant Design Pro | bool | false |
-ho | --host | Specify the hosting model | 'wasm' | 'server' | 'hosted' | 'wasm' |
--styles | Whether use NodeJS and Less to compile your custom themes. | css | less | css |
--no-restore | If specified, skips the automatic restore of the project on create | bool | false |
Go to the project folder of the application and install the Nuget package reference
$ dotnet add package AntDesign
Register the services in Program.cs
(client-side WebAssembly Blazor)
builder.Services.AddAntDesign();
or Startup.cs
(server-side Blazor)
services.AddAntDesign();
Link the static files in wwwroot/index.html
(client-side WebAssembly Blazor) or Pages/_Host.cshtml
(server-side Blazor)
<link href="_content/AntDesign/css/ant-design-blazor.css" rel="stylesheet" />
<script src="_content/AntDesign/js/ant-design-blazor.js"></script>
Add namespace in _Imports.razor
@using AntDesign
To display the pop-up component dynamically, you need to add the <AntContainer />
component in App.razor
.
<Router AppAssembly="@typeof(MainLayout).Assembly">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<Result Status="404" />
</LayoutView>
</NotFound>
</Router>
<AntContainer /> <-- add this component ✨
Finally, it can be referenced in the .razor
component!
<Button Type="@ButtonType.Primary">Hello World!</Button>
$ git clone git@github.com:ant-design-blazor/ant-design-blazor.git
$ cd ant-design-blazor
$ npm install
$ dotnet build ./site/AntDesign.Docs.Build/AntDesign.Docs.Build.csproj
$ npm start
Visual Studio 2022 is recommended for development.
Check out this issue to learn about our development plans for 2020.
Download Details:
Author: ant-design-blazor
Source Code: https://github.com/ant-design-blazor/ant-design-blazor
License: MIT, Unknown licenses found
#dotnet #aps.net #csharp #blazor
1656535920
A set of enterprise-class UI components based on Bootstrap and Blazor.
dotnet new -i Bootstrap.Blazor.Templates::*
dotnet new bbapp
Microsoft Market link
dotnet add package BootstrapBlazor
stylesheet
javascripts
file to your main index file - Pages/_Host.cshtml (Server)
or wwwroot/index.html (WebAssembly)
HTML
<!DOCTYPE html>
<html lang="en">
<head>
. . .
<link rel="stylesheet" href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css">
</head>
<body>
. . .
<script src="_framework/blazor.server.js"></script>
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
</body>
</html>
~/Startup.cs
file in the and register the Bootstrap Blazor
service:C#
namespace BootstrapBlazorAppName
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//more code may be present here
services.AddBootstrapBlazor();
}
//more code may be present here
}
}
To create a new Bootstrap Blazor
UI for Blazor application, use the Create New Project Wizard. The wizard detects all installed versions of Bootstrap Blazor
for Blazor and lists them in the Version combobox—this enables you to start your project with the desired version. You can also get the latest version to make sure you are up to date.
To use the Create New Project Wizard, install the Bootstrap Blazor
UI for Blazor Visual Studio Extensions. You can get it from the:
To start the wizard, use either of the following approaches
Chrome | Firefox | Safari | Android Browser & WebView | Microsoft Edge | |
---|---|---|---|---|---|
iOS | Supported | Supported | Supported | N/A | Supported |
Android | Supported | Supported | N/A | Android v5.0+ supported | Supported |
Windows 10 Mobile | N/A | N/A | N/A | N/A | Supported |
Chrome | Firefox | Internet Explorer | Microsoft Edge | Opera | Safari | |
---|---|---|---|---|---|---|
Mac | Supported | Supported | N/A | N/A | Supported | Supported |
Linux | Supported | Supported | N/A | N/A | N/A | N/A |
Windows | Supported | Supported | Supported, IE11+ | Supported | Supported | Not supported |
Download Details:
Author: dotnetcore
Source Code: https://github.com/dotnetcore/BootstrapBlazor
License: Apache-2.0 license
#dotnet #aps.net #csharp #blazor #bootstrap
1656528420
A F# implementation of the Hawk authentication protocol. Few dependencies. No cruft. No thrown exceptions.
If this library throws an exception, report an issue - instead it uses return values that are structured instead.
paket add nuget Hawk
paket add nuget Hawk.Suave
Dependencies: { Aether, FSharp.Core, NodaTime }, nugets Hawk and Hawk.Suave.
For all API methods implemented, the full test suite for those methods has also been translated.
Sponsored by qvitoo – A.I. bookkeeping.
open Logibit.Hawk
open Logibit.Hawk.Types
open Logibit.Hawk.Server
open Suave
open Suave.Http // houses submodule 'Hawk'
open Suave.Http.Successful
open Suave.Http.RequestErrors
open Suave.Types
// your own user type
type User =
{ homepage : Uri
realName : string }
// this is the structure that is the 'context' for Logibit.Hawk
let settings =
// this is what the lib is looking for to verify the request
let sampleCreds =
{ id = "haf"
key = "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn"
algorithm = SHA256 }
// the generic type param allows you to implement a generic user repository
// for your own user type (above)
{ Settings.empty<User>() with
// sign: UserId -> Choice<Credentials * 'a, CredsError>
credsRepo = fun id ->
(sampleCreds,
{ homepage = Uri("https://qvitoo.com"); realName = "Henrik" }
)
// no error:
|> Choice1Of2 }
// You can compose this into the rest of the app, as it's a web part. In this
// case you're doing a Authorization header authentication
let sampleApp settings : WebPart =
Hawk.authenticate
settings
Hawk.bindHeaderReq
// in here you can put your authenticated web parts
(fun (attr, creds, user) -> OK (sprintf "authenticated user '%s'" user.realName))
// on failure to authenticate the request
(fun err -> UNAUTHORIZED (err.ToString()))
// Similarly for bewits, where you want to authenticate a portion of the query
// string:
let sampleApp2 settings : WebPart =
Hawk.authenticateBewit
settings Hawk.bindQueryRequest
// in here you can put your authenticated web parts
(fun (attr, creds, user) -> OK (sprintf "authenticated user '%s'" user.realName))
// on failure to authenticate the request
(fun err -> UNAUTHORIZED (err.ToString()))
Currently the code is only fully documented - but not outside the code, so have a browse to the source code that you are interested in to see how the API composes.
Use the .js file from src/vendor/hawk.js/lib
, then you can wrap your ajax calls like this:
request.js: (using CommonJS module layout, which you can use to require it and get a function in return).
var Auth = require('./auth.js'),
Hawk = require('./lib/hawk.js'),
Logger = require('./logger.js'),
jQuery = require('jquery');
var qt = function(str) {
return "'" + str + "'";
}
var jqSetHawkHeader = function(opts, creds, jqXHR, settings) {
if (typeof opts.contentType == 'undefined') {
throw new Error('missing contentType from options');
}
var opts = jQuery.extend({ credentials: creds, payload: settings.data }, opts),
// header(uri, method, options): should have options values for
// - contentType
// - credentials
// - payload
header = Hawk.client.header(settings.url, settings.type, opts); // type = HTTP-method
if (typeof header.err !== 'undefined') {
Logger.error('(1/2) Hawk error:', qt(header.err), 'for', method, qt(settings.url));
Logger.error('(2/2) Using credentials', opts.credentials);
return;
}
Logger.debug('(1/3)', settings.type, settings.url);
Logger.debug('(2/3) opts:', opts);
Logger.debug('(3/3) header:', header.field);
jqXHR.setRequestHeader('Authorization', header.field);
};
module.exports = function (method, resource, data, opts) {
var origin = window.location.origin,
creds = Auth.getCredentials(),
url = origin + resource,
opts = jQuery.extend({
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
dataType: 'html'
}, (typeof opts !== 'undefined' ? opts : {})),
jqOpts = jQuery.extend({
type: method,
data: data,
url: url,
beforeSend: function(xhr, s) { jqSetHawkHeader(opts, creds, xhr, s) }
}, opts);
return jQuery.ajax(jqOpts);
};
Please have a look at Releases.
This is the public API of the library. It mimics the API of Hawk.js - the reference implementation.
Logibit.Hawk.Bewit
These functions are available to creating and verifying Bewits.
authenticate
detailsTBD - docs, in the meanwhilse, see Server authenticate (superset is validated).
Logibit.Hawk.Client
These functions are available, checked functions are implemented
Logibit.Hawk.Server
authenticate
to get credentials. Payload Validationauthenticate
detailsHow strictly does the server validate its input? Compared to reference implementation. This part is important since it will make or break the usability of your api/app. Just throwing SecurityException for any of these is not granular enough.
FaultyAuthorizationHeader
FaultyAuthorizationHeader
MissingAttribute
CredsError
BadMac
MissingAttribute
BadPayloadHash of hash_given * hash_calculated
NonceError AlreadySeen
, with in-memory cacheStaleTimestamp
Hints when not under attack (in dev)
If you see CredsError
, it's most likely a problem that you can't find the user with your repository function.
If you see BadMac
, it means probably means you haven't fed the right parameters to authenticate
. Log the input parameters, verify that host and port match (are you behind a reverse proxy?) and check that the length of the content is the same on the client as on the server.
The BadMac
error comes from hashing a normalised string of these parameters:
If you see PadPayloadHash, it means that the MAC check passed, so you're probably looking at an empty byte array, or your Content-Type isn't being passed to the server properly, or the server implementation doesn't feed the correct Content-Type header (e.g. it doesn't trim the stuff after the first MimeType declaration, before the semi-colon ;
).
Logibit.Hawk.Crypto
The crypto module contains functions for validating the pieces of the request.
Logibit.Hawk.Types
This module contains the shared types that you should use for interacting with the above modules.
This module also contains a module-per-type with lenses for that type. The lenses follow the same format as Aether recommends.
Logibit.Hawk.Logging
Types:
LogLevel
- the level of the LogLine.LogLine
- this is the data structure of the logging module, this is where you feed your data.Logger interface
- the main interface that we can log to/into.Logger module
- a module that contains functions equiv. to the instance methods of the logger interface.NoopLogger : Logger
- the default logger, you have to replace it yourselfIt's good to know that you have to construct your LogLine yourself. That LogLines with Verbose or Debug levels should be sent to the debug
or verbose
functions/methods of the module/interface Logger, which in turn takes functions, which are evaluated if it's the case that the logging infrastructure is indeed logging at that level.
This means that logging at that level, and computing the log lines, needs only be done if we can really do something with them.
There are some modules that are currently internal as to avoid conflicting with existing code. If these are made 'more coherent' or else moved to external libraries, they can be placed on their own and be made public. The modules like this are Random
, Prelude
, Parse
.
Download Details:
Author: logibit
Source Code: https://github.com/logibit/logibit.hawk/
License: View license
#dotnet #aps.net #csharp
1656521054
Very simple SAML 2.0 "consumer" implementation in C#.
It's a SAML client library, not a SAML server, allows adding SAML single-sign-on to your ASP.NET app, but not to provide auth services to other apps.
Consists of one short C# file you can throw into your project (or install via nuget) and start using it. It works with both ASP.NET Core and the "old" ASP.NET Framework
SAML workflow has 2 steps:
Here's how you do it (this example is for ASP.NET MVC):
//this example is an ASP.NET MVC action method
public ActionResult Login()
{
//TODO: specify the SAML provider url here, aka "Endpoint"
var samlEndpoint = "http://saml-provider-that-we-use.com/login/";
var request = new AuthRequest(
"http://www.myapp.com", //TODO: put your app's "entity ID" here
"http://www.myapp.com/SamlConsume" //TODO: put Assertion Consumer URL (where the provider should redirect users after authenticating)
);
//redirect the user to the SAML provider
return Redirect(request.GetRedirectUrl(samlEndpoint));
}
User is sent back to your app - you need to validate the SAML response ("assertion") that you recieved via POST.
Here's an example of how you do it in ASP.NET MVC
//ASP.NET MVC action method... But you can easily modify the code for Web-forms etc.
public ActionResult SamlConsume()
{
// 1. TODO: specify the certificate that your SAML provider gave you
string samlCertificate = @"-----BEGIN CERTIFICATE-----
BLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAH123543==
-----END CERTIFICATE-----";
// 2. Let's read the data - SAML providers usually POST it into the "SAMLResponse" var
var samlResponse = new Response(samlCertificate, Request.Form["SAMLResponse"]);
// 3. We're done!
if (samlResponse.IsValid())
{
//WOOHOO!!! user is logged in
username = samlResponse.GetNameID();
}
}
Reading more attributes from the provider
SAML providers usually send more data with their response: username, first/last names etc. Here's how to get it:
if (samlResponse.IsValid())
{
//WOOHOO!!! user is logged in
//Some more optional stuff for you
//let's extract username/firstname etc
string username, email, firstname, lastname;
try
{
username = samlResponse.GetNameID();
email = samlResponse.GetEmail();
firstname = samlResponse.GetFirstName();
lastname = samlResponse.GetLastName();
}
catch(Exception ex)
{
//insert error handling code
//no, really, please do
return null;
}
//user has been authenticated, put your code here, like set a cookie or something...
//or call FormsAuthentication.SetAuthCookie()
//or call context.SignInAsync() in ASP.NET Core
//or do something else
}
Depending on your .NET version, your Project should reference System.Security
for .NET Framework and System.Security.Cryptography.Xml
for .NET Core.
I've published this to Nuget.
Install-Package AspNetSaml
This will simply add the cs-file to the root of your project.
A version of this library has been used for years in production in our helpdesk app.
Download Details:
Author: jitbit
Source Code: https://github.com/jitbit/AspNetSaml
License: Apache-2.0 license
#dotnet #aps.net #csharp
1656513678
Bundle Transformer - a modular extension for the System.Web.Optimization (also known as the Microsoft ASP.NET Web Optimization Framework). StyleTransformer
and ScriptTransformer
classes, included in the core of Bundle Transformer and implement the IBundleTransform
interface. They are intended to replace the standard classes: CssMinify
and JsMinify
.
The main differences of the StyleTransformer
and ScriptTransformer
classes from a standard implementations: ability to exclude unnecessary assets when adding assets from a directory, does not produce the re-minification of pre-minified assets, support automatic transformation of relative paths to absolute in CSS code (by using the UrlRewritingCssPostProcessor
), etc. These classes do not produce the minification of code in runtime, but this feature can be added by installing of minifier-modules (now available modules based on Microsoft Ajax Minifier, YUI Compressor for .NET, NUglify, Google Closure Compiler, Douglas Crockford's JSMin, Dean Edwards' Packer, Mihai Bazon's UglifyJS, Sergey Kryzhanovsky's CSSO (CSS Optimizer), WebGrease and Clean-css). In addition, you can also install translator-modules, that implement the translation of code on intermediate languages (LESS, Sass, SCSS, CoffeeScript, TypeScript, Mustache (by using Hogan) and Handlebars). Apart from this, in the Bundle Transformer there is a third type of modules - postprocessors. Postprocessors runs after translators and before minifiers. Now available following postprocessors: URL rewriting CSS postprocessor (included in core) and postprocessor-module based on the Andrey Sitnik's Autoprefixer.
This extension will help your web applications successfully pass a most part of the tests in Google PageSpeed.
Documentation is located on the wiki of this Repo.
See the changelog.
If you use Bundle Transformer in some project, please send me a message so I can include it in this list:
Bundle Transformer was created and is maintained by Andrey Taritsyn.
Download Details:
Author: Taritsyn
Source Code: https://github.com/Taritsyn/BundleTransformer
License: Apache-2.0 license
#dotnet #aps.net #csharp
1656507369
C# Wrapper for the official Binance exchange API
Compatible with .NET 4.5.1, .NET 4.5.2, .NET 4.6.1, .NETSTANDARD2.0
This repository provides a C# wrapper for the official Binance API, and provides rate limiting features (set to 10 by 10 out the box), a IAPICacheManager
interface to allow users to provide their own cache implementations, all REST
endpoints covered, and a best practice solution coupled with strongly typed responses and requests. It is built on the latest .NET Framework and in .NET Core
Feel free to raise issues and Pull Request to help improve the library. If you found this API useful, and you wanted to give back feel free to sign up to Binance via my referral link here.
The package is available in NuGet, or feel free to download: https://www.nuget.org/packages/BinanceDotNet/
Nuget PM
Install-Package BinanceDotNet
dotnet cli
dotnet add package BinanceDotNet
Upkeep of this API takes a lot of time from answering issues and PR's on the Repository, as well as tweets and direct emails. You can donate cryptocurrency of any amount to the following wallets:
ETH: 0xd5775e2dee4b9fa9a3be5222970c04ac574e8412
Want to send something else? Just tweet me! @Glitch100
Or you can help maintain the repository! Donations of time are welcome, just hit me up and we can work on it. From answering issues, to contributing code anyone can assist.
git clone git@github.com:glitch100/BinanceDotNet.git
ExampleProgram.cs
log4net
Interfaces supportedIAPICacheManager
abstraction for providing your own cache or using the build in concrete implementation. (Currently only one endpoint has caching)More examples are available to play around with within the repositorys Console application which can be found here. Otherwise there are some examples around utilising both WebSockets
and REST
API in the Usage
section below.
Work will continue on this API wrapper over the coming months adding and extending out the number of features that the BinanceDotNet
library has. Please raise issues for new features desired
Code examples below, or clone the repository and run the BinanceExchange.Console
project. This repository is built off dotnet core, and runs against C# 7.1
General usage just requires setting up the client with your credentials, and then calling the Client as necessary.
// Build out a client, provide a logger, and more configuration options, or even your own APIProcessor implementation
var client = new BinanceClient(new ClientConfiguration()
{
ApiKey = "YOUR_API_KEY",
SecretKey = "YOUR_SECRET_KEY",
});
//You an also specify symbols like this.
var desiredSymbol = TradingPairSymbols.BNBPairs.BNB_BTC,
IReponse response = await client.GetCompressedAggregateTrades(new GetCompressedAggregateTradesRequest(){
Symbol = "BNBBTC",
StartTime = DateTime.UtcNow().AddDays(-1),
EndTime = Date.UtcNow(),
});
For WebSocket endpoints, just instantiate the BinanceClient
, and provide it into the BinanceWebSocketClient
You can use a using
block or manual management.
var client = new BinanceClient(new ClientConfiguration()
{
ApiKey = "YOUR_API_KEY",
SecretKey = "YOUR_SECRET_KEY",
});
// Manual management
var manualWebSocketClient = new InstanceBinanceWebSocketClient(client);
var socketId = binanceWebSocketClient.ConnectToDepthWebSocket("ETHBTC", data =>
{
System.Console.WriteLine($"DepthCall: {JsonConvert.SerializeObject(data)}");
});
manualWebSocketClient.CloseWebSocketInstance(socketId);
// Disposable and managed
using (var binanceWebSocketClient = new DisposableBinanceWebSocketClient(client))
{
binanceWebSocketClient.ConnectToDepthWebSocket("ETHBTC", data =>
{
System.Console.WriteLine($"DepthCall: {JsonConvert.SerializeObject(data)}");
});
Thread.Sleep(180000);
}
The Binance API provides rich exceptions based on different error types. You can decorate calls like this if you would like to handle the various exceptions.
// Firing off a request and catching all the different exception types.
try
{
accountTrades = await client.GetAccountTrades(new AllTradesRequest()
{
FromId = 352262,
Symbol = "ETHBTC",
});
}
catch (BinanceBadRequestException badRequestException)
{
}
catch (BinanceServerException serverException)
{
}
catch (BinanceTimeoutException timeoutException)
{
}
catch (BinanceException unknownException)
{
}
The example is mainly 'all in one' so you can see a full runthrough of how it works. In your own implementations you may want to have a cache of only the most recent bids/asks, or perhaps will want the empty quanity/price trades.
You can also calculate volume and more from this cache. The following code is partial from the ExampleProgram.cs
.
private static async Task<Dictionary<string, DepthCacheObject>> BuildLocalDepthCache(IBinanceClient client)
{
// Code example of building out a Dictionary local cache for a symbol using deltas from the WebSocket
var localDepthCache = new Dictionary<string, DepthCacheObject> {{ "BNBBTC", new DepthCacheObject()
{
Asks = new Dictionary<decimal, decimal>(),
Bids = new Dictionary<decimal, decimal>(),
}}};
var bnbBtcDepthCache = localDepthCache["BNBBTC"];
// Get Order Book, and use Cache
var depthResults = await client.GetOrderBook("BNBBTC", true, 100);
//Populate our depth cache
depthResults.Asks.ForEach(a =>
{
if (a.Quantity != 0.00000000M)
{
bnbBtcDepthCache.Asks.Add(a.Price, a.Quantity);
}
});
depthResults.Bids.ForEach(a =>
{
if (a.Quantity != 0.00000000M)
{
bnbBtcDepthCache.Bids.Add(a.Price, a.Quantity);
}
});
// Store the last update from our result set;
long lastUpdateId = depthResults.LastUpdateId;
using (var binanceWebSocketClient = new DisposableBinanceWebSocketClient(client))
{
binanceWebSocketClient.ConnectToDepthWebSocket("BNBBTC", data =>
{
if (lastUpdateId < data.UpdateId)
{
data.BidDepthDeltas.ForEach((bd) =>
{
CorrectlyUpdateDepthCache(bd, bnbBtcDepthCache.Bids);
});
data.AskDepthDeltas.ForEach((ad) =>
{
CorrectlyUpdateDepthCache(ad, bnbBtcDepthCache.Asks);
});
}
lastUpdateId = data.UpdateId;
System.Console.Clear();
System.Console.WriteLine($"{JsonConvert.SerializeObject(bnbBtcDepthCache, Formatting.Indented)}");
System.Console.SetWindowPosition(0, 0);
});
Thread.Sleep(8000);
}
return localDepthCache;
}
You can use the data returned from above to utilise the ResultTransformations
static
class, to transform data returned from the API into more meaningful, known shapes, such as Volume etc.
// This builds a local depth cache from an initial call to the API and then continues to fill
// the cache with data from the WebSocket
var localDepthCache = await BuildLocalDepthCache(client);
// Build the Buy Sell volume from the results
var volume = ResultTransformations.CalculateTradeVolumeFromDepth("BNBBTC", localDepthCache);
Download Details:
Author: binance-exchange
Source Code: https://github.com/binance-exchange/BinanceDotNet
License: MIT license
#Binance #blockchain #dotnet #csharp
1656506068
DotNetty is a port of Netty, asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.
We gladly accept community contributions.
Download Details:
Author: Azure
Source Code: https://github.com/Azure/DotNetty
License: View license
#dotnet #aps.net #csharp
1656386666
Fritz has built a website to manage your collection, but how can we open up the website with an API to allow other integrations? In this session, Fritz adds an API to our website using ASP.NET Core
#aspnetcore #api #dotnet #csharp #webdev
1656050040
Playwright for .NET 🎭
Playwright for .NET is the official language port of Playwright, the library to automate Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast.
Linux | macOS | Windows | |
---|---|---|---|
Chromium 103.0.5060.24 | ✅ | ✅ | ✅ |
WebKit 15.4 | ✅ | ✅ | ✅ |
Firefox 99.0.1 | ✅ | ✅ | ✅ |
https://playwright.dev/dotnet/docs/api/class-playwright
using System.Threading.Tasks;
using Microsoft.Playwright;
class Program
{
public static async Task Main()
{
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new() { Headless = false });
var page = await browser.NewPageAsync();
await page.GotoAsync("https://playwright.dev/dotnet");
await page.ScreenshotAsync(new() { Path = "screenshot.png" });
}
}
More comfortable in another programming language? Playwright is also available in
https://playwright.dev/dotnet/docs/intro
Author: Microsoft
Source Code: https://github.com/microsoft/playwright-dotnet
License: MIT license
1655982600
Swagger(OpenAPI)は、RESTAPIを記述するための言語に依存しない仕様です。これにより、コンピューターと人間の両方が、ソースコードに直接アクセスしなくてもRESTAPIの機能を理解できます。Swagger UIは、生成されたOpenAPI仕様を使用して、サービスに関する情報を提供するWebベースのUIを提供します。SwaggerUIはPostmanの代替手段です。
私は自分の記事でSwaggerを数回以上使用しましたが、さまざまなトピックで使用されるマイナーなツールとして使用しました。Swaggerの情報を取得しようとしたとき、これらの記事から検索する必要がありましたが、これは便利ではありませんでした。そこで、これら2つの記事、特にSwagger for .NET MVCWebAPIまたは.NETCoreMVCWebAPIについて書き直しました。
新しい.NETCore5.0 Web APIプロジェクトを作成した場合、WebAPI用のSwaggercientがデフォルトでインストールされます。現在のケースでは、.NET Core 5.0を使用していますが、Web APIはMVCモジュールで作成されているため、Swaggerを手動でインストールする必要があります。この方法は、5.0より前の.NETCoreバージョンで機能します。
この記事は、私の別の記事の一部です 。MVCによるWeb APIの使用.NETCore(1)、サーバー、およびフレームワークでは、Swagger関連の部分がここにあります。そこから詳細を見ることができます。
アプリのビルドには、Visual Studio201916.8と.NET5.0SDKのバージョンを使用します。
MVCCallWebAPI
プロジェクト名を入力します。アプリをビルドして実行すると、次の画像にアプリが表示されます。
記事「 .NETCore(1)、サーバーおよびフレームワークでMVCによるWebAPIの消費」を参照してください 。
1.Swaggerクライアントをインストールします
ソリューションエクスプローラー>[NuGetパッケージの管理]でプロジェクトを右クリックし、 Swaggerを検索します
Swashbuckle(Swagger)には3つの主要なコンポーネントがあり、そのうちの2つをインストールするだけで済みます。SwaggerGenとSwaggerUIで、Swaggerが含まれます。
2.startup.cs ファイルにSwaggerクライアントを登録し ます
Startup.ConfigureServices
メソッドのサービスコレクションにSwaggerジェネレーターを追加します 。
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v2", new OpenApiInfo { Title = "MVCCallWebAPI", Version = "v2" });
});
......
}
Startup.Configure
メソッドで、生成されたJSONドキュメントとSwaggerUIを提供するためのミドルウェアを有効にします 。
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v2/swagger.json", "MVCCallWebAPI");
});
......
}
これで、アプリを実行する準備がほぼ整いました。
アプリを実行する前に、ファイルのヘッダーを変更します 。Views/ Shared / _layout.cshtml Viewsを再度変更して、以下に示すSwagger(11〜13行目)を追加します。
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="StoresMVC" asp-action="Index">MVC app</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Swagger" asp-action="Index">Web API</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
次に、アプリを実行します。
Web APIをクリックすると、Swaggerクライアント画面が表示されます。
ソース:https ://www.c-sharpcorner.com/article/swagger-for-net-core-mvc-web-api/
1655982000
Swagger (OpenAPI) é uma especificação independente de linguagem para descrever APIs REST. Ele permite que computadores e humanos entendam os recursos de uma API REST sem acesso direto ao código-fonte. Swagger UI oferece uma UI baseada na web que fornece informações sobre o serviço, usando a especificação OpenAPI gerada. Swagger UI é uma alternativa ao Postman.
Usei o Swagger várias vezes em meus artigos, mas apenas como uma ferramenta menor usada em diferentes tópicos. Quando tentei obter informações do Swagger, tive que pesquisar nesses artigos, que não eram convenientes. Então, reescrevo esses dois artigos, especialmente sobre Swagger para .NET MVC Web API ou .NET Core MVC Web API.
Se tivéssemos criado um novo projeto de API Web .NET Core 5.0, o Swagger cient for Web API seria instalado por padrão. Em nosso caso atual, embora usemos o .NET Core 5.0, a API da Web é criada em um módulo MVC, portanto, precisamos instalar o Swagger manualmente. Dessa forma, funcionará para a versão .NET Core anterior à 5.0.
Este artigo é parte do meu outro artigo: Consumir Web API por MVC No .NET Core (1), Server And Framework , temos aqui a parte relacionada ao Swagger. Você pode ver detalhes de lá.
Usamos a versão do Visual Studio 2019 16.8 e .NET 5.0 SDK para compilar o aplicativo.
MVCCallWebAPI
o nome do projeto.Compile e execute o aplicativo, você verá a imagem a seguir mostra o aplicativo,
Consulte o artigo Consume Web API By MVC In .NET Core (1), Server And Framework ,
1. Instale o cliente Swagger
Clique com o botão direito do mouse no projeto em Solution Explorer > Manage NuGet Packages, procure Swagger
Existem três componentes principais para o Swashbuckle (Swagger), precisamos apenas instalar dois deles: SwaggerGen e SwaggerUI, o Swagger seria incluído.
2. Registre o Swagger Client no arquivo startup.cs
Adicione o gerador Swagger à coleção de serviços no Startup.ConfigureServices
método,
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v2", new OpenApiInfo { Title = "MVCCallWebAPI", Version = "v2" });
});
......
}
Habilite o middleware para servir o documento JSON gerado e a UI Swagger, no Startup.Configure
método,
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v2/swagger.json", "MVCCallWebAPI");
});
......
}
Agora, estamos quase prontos para executar o aplicativo.
Antes de executarmos o aplicativo, modifique o cabeçalho do arquivo: Views/Shared/_layout.cshtml Views novamente para adicionar Swagger (linha 11~13), mostrado abaixo,
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="StoresMVC" asp-action="Index">MVC app</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Swagger" asp-action="Index">Web API</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
Agora, executamos o aplicativo,
Clique em Web API, temos a tela do Swagger Client,
Fonte: https://www.c-sharpcorner.com/article/swagger-for-net-core-mvc-web-api/
1655929800
Nous allons discuter de la mise en cache dans .NET Core et de son fonctionnement. Donc, nous regardons les choses suivantes une par une.
Alors, commençons un par un.
La mise en cache est très populaire de nos jours dans l'industrie du logiciel car elle améliore les performances et l'évolutivité de l'application. Nous utilisons de nombreuses applications Web comme Gmail et Facebook et voyons à quel point elles sont réactives et nous avons une excellente expérience utilisateur. De nombreux utilisateurs utilisent Internet et si une application a un trafic réseau et une demande énormes, nous devons nous occuper de beaucoup de choses qui nous aident à améliorer les performances et la réactivité de l'application. Donc, à cause de cela, il y a la solution de la mise en cache et c'est pourquoi la mise en cache entre en jeu.
Le cache est le stockage de mémoire utilisé pour stocker les données d'accès fréquentes dans le stockage temporaire, il améliorera considérablement les performances et évitera les accès inutiles à la base de données et stockera les données fréquemment utilisées dans le tampon chaque fois que nous en aurons besoin.
Comme vous le voyez dans l'image ci-dessus, il existe deux scénarios, l'un sans utiliser de cache et l'autre avec cache. Donc, ici, lorsque nous n'utilisons pas le cache, dans ce cas, supposons que les utilisateurs veulent des données, ils frapperont à chaque fois la base de données et cela augmentera la complexité temporelle et réduira les performances au cas où il y aurait des données statiques que les utilisateurs voudraient et c'est la même chose pour tous les utilisateurs. Dans ce cas, lorsque nous n'utilisons pas de cache, chacun accède à la base de données inutile pour récupérer des données. De l'autre côté, comme vous pouvez le voir, nous utilisons le cache, et dans ce cas s'il y a les mêmes données statiques et les mêmes pour tous les utilisateurs, seul le premier utilisateur accédera à la base de données et récupérera les données et les stockera dans la mémoire cache, puis deux autres utilisateurs l'ont utilisé à partir du cache sans toucher inutilement à la base de données pour récupérer des données.
Fondamentalement, il existe deux types de prise en charge de la mise en cache de .NET Core
Lorsque nous utilisons le cache en mémoire, dans ce cas, les données sont stockées dans la mémoire du serveur d'applications et chaque fois que nous en avons besoin, nous récupérons les données et les utilisons partout où nous en avons besoin. Et dans la mise en cache distribuée, il existe de nombreux mécanismes tiers comme Redis et bien d'autres. Mais dans cette section, nous examinons en détail le cache Redis et son fonctionnement dans .NET Core
Redis est le cache le plus populaire utilisé par de nombreuses entreprises de nos jours pour améliorer les performances et l'évolutivité de l'application. Nous allons donc discuter de Redis et de son utilisation un par un.
Étape 1
Téléchargez le serveur Redis à l'aide de l'URL suivante
https://github.com/microsoftarchive/redis/releases/tag/win-3.0.504
Étape 2
Extrayez le fichier zip et ouvrez plus tard le serveur Redis et la CLI Redis
Étape 1
Créer l'application Web de l'API .NET Core
Étape 2
Installez les packages NuGet suivants qui nécessitent étape par étape dans notre application
Étape 3
Créez le dossier Modèle et créez une classe de produits à l'intérieur avec des détails
namespace RedisCacheDemo.Model
{
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public int Stock { get; set; }
}
}
Étape 4
Ensuite, créez la classe DbContextClass pour les opérations liées à la base de données comme je l'ai montré ci-dessous
using Microsoft.EntityFrameworkCore;
using RedisCacheDemo.Model;
namespace RedisCacheDemo.Data {
public class DbContextClass: DbContext {
public DbContextClass(DbContextOptions < DbContextClass > options): base(options) {}
public DbSet < Product > Products {
get;
set;
}
}
}
Étape 5
Maintenant, nous allons créer l'interface ICacheService et la classe CacheService pour une utilisation liée au cache Redis.
using System;
namespace RedisCacheDemo.Cache
{
public interface ICacheService
{
/// <summary>
/// Get Data using key
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
T GetData<T>(string key);
/// <summary>
/// Set Data with Value and Expiration Time of Key
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expirationTime"></param>
/// <returns></returns>
bool SetData<T>(string key, T value, DateTimeOffset expirationTime);
/// <summary>
/// Remove Data
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
object RemoveData(string key);
}
}
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
namespace RedisCacheDemo.Cache {
public class CacheService: ICacheService {
private IDatabase _db;
public CacheService() {
ConfigureRedis();
}
private void ConfigureRedis() {
_db = ConnectionHelper.Connection.GetDatabase();
}
public T GetData < T > (string key) {
var value = _db.StringGet(key);
if (!string.IsNullOrEmpty(value)) {
return JsonConvert.DeserializeObject < T > (value);
}
return default;
}
public bool SetData < T > (string key, T value, DateTimeOffset expirationTime) {
TimeSpan expiryTime = expirationTime.DateTime.Subtract(DateTime.Now);
var isSet = _db.StringSet(key, JsonConvert.SerializeObject(value), expiryTime);
return isSet;
}
public object RemoveData(string key) {
bool _isKeyExist = _db.KeyExists(key);
if (_isKeyExist == true) {
return _db.KeyDelete(key);
}
return false;
}
}
}
Étape 6
Créez la classe ProductController et créez la méthode suivante comme indiqué ci-dessous
using Microsoft.AspNetCore.Mvc;
using RedisCacheDemo.Cache;
using RedisCacheDemo.Data;
using RedisCacheDemo.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace RedisCacheDemo.Controllers {
[Route("api/[controller]")]
[ApiController]
public class ProductController: ControllerBase {
private readonly DbContextClass _dbContext;
private readonly ICacheService _cacheService;
public ProductController(DbContextClass dbContext, ICacheService cacheService) {
_dbContext = dbContext;
_cacheService = cacheService;
}
[HttpGet("products")]
public IEnumerable < Product > Get() {
var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
if (cacheData != null) {
return cacheData;
}
var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
cacheData = _dbContext.Products.ToList();
_cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime);
return cacheData;
}
[HttpGet("product")]
public Product Get(int id) {
Product filteredData;
var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
if (cacheData != null) {
filteredData = cacheData.Where(x => x.ProductId == id).FirstOrDefault();
return filteredData;
}
filteredData = _dbContext.Products.Where(x => x.ProductId == id).FirstOrDefault();
return filteredData;
}
[HttpPost("addproduct")]
public async Task < Product > Post(Product value) {
var obj = await _dbContext.Products.AddAsync(value);
_cacheService.RemoveData("product");
_dbContext.SaveChanges();
return obj.Entity;
}
[HttpPut("updateproduct")]
public void Put(Product product) {
_dbContext.Products.Update(product);
_cacheService.RemoveData("product");
_dbContext.SaveChanges();
}
[HttpDelete("deleteproduct")]
public void Delete(int Id) {
var filteredData = _dbContext.Products.Where(x => x.ProductId == Id).FirstOrDefault();
_dbContext.Remove(filteredData);
_cacheService.RemoveData("product");
_dbContext.SaveChanges();
}
}
}
Étape 7
Ajoutez la chaîne de connexion SQL Server et l'URL Redis dans appsetting.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"RedisURL": "127.0.0.1:6379",
"ConnectionStrings": {
"DefaultConnection": "Data Source=Server;Initial Catalog=RedisCache;User Id=sa;Password=***;"
}
}
Étape 8
Ensuite, enregistrez ICacheService dans la méthode Configure Service de Startup Class et ajoutez également une configuration liée à Swagger pour tester nos points de terminaison API.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using RedisCacheDemo.Cache;
using RedisCacheDemo.Data;
namespace RedisCacheDemo {
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration {
get;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
services.AddScoped < ICacheService, CacheService > ();
services.AddDbContext < DbContextClass > (options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new OpenApiInfo {
Title = "RedisCacheDemo", Version = "v1"
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "RedisCacheDemo v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
}
}
}
Étape 9
Créez une classe ConfigurationManger pour configurer les paramètres de l'application là-bas
using Microsoft.Extensions.Configuration;
using System.IO;
namespace RedisCacheDemo {
static class ConfigurationManager {
public static IConfiguration AppSetting {
get;
}
static ConfigurationManager() {
AppSetting = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
}
}
}
Étape 10
Ensuite, créez une classe d'assistance de connexion pour la connexion Redis
using StackExchange.Redis;
using System;
namespace RedisCacheDemo.Cache {
public class ConnectionHelper {
static ConnectionHelper() {
ConnectionHelper.lazyConnection = new Lazy < ConnectionMultiplexer > (() => {
return ConnectionMultiplexer.Connect(ConfigurationManager.AppSetting["RedisURL"]);
});
}
private static Lazy < ConnectionMultiplexer > lazyConnection;
public static ConnectionMultiplexer Connection {
get {
return lazyConnection.Value;
}
}
}
}
Étape 11
Effectuez la migration et la mise à jour de la base de données pour la création de la base de données à l'aide des commandes suivantes dans la console du gestionnaire de packages.
add-migration "FirstMigration"
mise à jour de la base de données
Ainsi, lorsque vous entrez et exécutez cette commande, elle génère quelques éléments liés à la migration et crée la base de données dans SQL Server lorsque vous placez la chaîne de connexion dans le fichier appsetting.json.
Étape 12
Enfin, exécutez l'application et ajoutez les données à l'aide de l'interface utilisateur swagger, puis vérifiez le fonctionnement de la mise en cache dans les produits et le point de terminaison du produit.
Fondamentalement, j'ai ajouté du cache dans les points de terminaison du produit et des produits dans le contrôleur, comme vous le voyez lorsque l'utilisateur veut récupérer les données de tous les produits, il vérifiera d'abord si les données sont présentes dans le cache Redis ou non et si elles sont présentes dans le cache renvoie ensuite ces données à l'utilisateur et si les données ne sont pas présentes dans le cache, il récupère les données de la base de données et les place également dans le cache. Ainsi, la prochaine fois, l'utilisateur obtiendra cela uniquement à partir du cache et évitera d'accéder inutilement à la base de données
De plus, lorsque l'utilisateur souhaite récupérer des données à l'aide de l'identifiant du produit, comme vous le voyez dans le contrôleur du deuxième point de terminaison du produit, nous récupérons les données du cache de tous les produits, puis les filtrons à l'aide de l'identifiant du produit et, si cela se présente, revenons à l'utilisateur à partir du cache et pas ensuite récupérer de la base de données et revenir à l'utilisateur après avoir appliqué le filtre.
Ainsi, comme vous le voyez à l'intérieur de la mise à jour, de la suppression et de la publication du point de terminaison du contrôleur de produit, nous utilisons la méthode de suppression pour supprimer les données de la clé de produit qui sont présentes dans le cache. Ainsi, il existe de nombreux scénarios et utilisations de caches mémoire que vous pouvez utiliser selon vos besoins et vos exigences. Je veux juste présenter les bases du cache Redis et son fonctionnement à l'intérieur du .NET Core que j'ai couvert ici.
En outre, vous devez prendre en compte un scénario lors de l'utilisation de la mise en cache. Supposons que deux utilisateurs utilisent votre application, les scénarios suivants se produiront.
Créez cet objet privé de verrou au-dessus de la classe
private static object _lock = new object()
Ensuite, modifiez la méthode Get comme je l'ai montré ci-dessous
public IEnumerable < Product > Get() {
var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
if (cacheData != null) {
return cacheData;
}
lock(_lock) {
var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
cacheData = _dbContext.Products.ToList();
_cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime);
}
return cacheData;
}
Donc, ici, comme vous le voyez, nous vérifions d'abord si les données sont présentes dans le cache ou non si les données sont disponibles, puis nous les renvoyons. Ensuite, si la valeur n'est pas présente dans le cache Redis, nous appliquons le verrou là-bas, puis la demande est verrouillée et entrée dans la section et récupère les détails du produit dans la base de données, puis la définit également dans le cache, puis retourner les données. Alors, que s'est-il passé lorsque le deuxième utilisateur envoie une demande avant que la demande de l'utilisateur ne soit terminée. Ainsi, dans ce cas, la deuxième demande est dans la file d'attente et après avoir terminé la première demande de l'utilisateur, la deuxième demande entre en scène
En outre, vous pouvez voir les détails clés déjà présents dans Redis à l'aide de la CLI Redis, comme indiqué ci-dessous.
Donc, ici, vous pouvez voir qu'il existe de nombreuses commandes qui nous fournissent des informations sur les clés présentes dans le cache Redis.
Il s'agit du cache Redis dans .NET Core. J'espère que vous comprenez les choses liées à cela.
Bon codage !
Source : https://www.c-sharpcorner.com/article/implementation-of-the-redis-cache-in-the-net-core-api/
1655929440
Chúng ta sẽ thảo luận về bộ nhớ đệm trong .NET Core và cách thức hoạt động của nó. Vì vậy, chúng ta xem xét từng thứ sau đây.
Vì vậy, chúng ta hãy bắt đầu từng cái một.
Bộ nhớ đệm ngày nay rất phổ biến trong ngành công nghiệp phần mềm vì nó sẽ cải thiện hiệu suất và khả năng mở rộng của ứng dụng. Chúng tôi sử dụng nhiều ứng dụng web như Gmail và Facebook và xem chúng phản hồi như thế nào và chúng tôi có trải nghiệm người dùng tuyệt vời. Có rất nhiều người dùng sử dụng Internet và nếu một ứng dụng có nhu cầu và lưu lượng mạng lớn, chúng ta cần quan tâm đến nhiều thứ để giúp chúng ta cải thiện hiệu suất và khả năng phản hồi của ứng dụng. Vì vậy, do đó, có giải pháp bộ nhớ đệm và đó là lý do tại sao bộ nhớ đệm xuất hiện trong bức tranh.
Bộ nhớ đệm là bộ nhớ lưu trữ được sử dụng để lưu trữ dữ liệu truy cập thường xuyên vào bộ lưu trữ tạm thời, nó sẽ cải thiện hiệu suất đáng kể và tránh bị tấn công cơ sở dữ liệu không cần thiết và lưu trữ dữ liệu thường xuyên sử dụng vào bộ đệm bất cứ khi nào chúng ta cần.
Như bạn thấy trong hình trên, có hai trường hợp, một là không sử dụng bộ nhớ cache và một trường hợp khác là với bộ nhớ cache. Vì vậy, ở đây khi chúng ta không sử dụng bộ nhớ cache, trong trường hợp đó, giả sử người dùng muốn có dữ liệu thì họ sẽ truy cập vào cơ sở dữ liệu mỗi lần và nó sẽ làm tăng độ phức tạp về thời gian và giảm hiệu suất trong trường hợp có một số dữ liệu tĩnh mà người dùng muốn và điều đó cũng tương tự đối với tất cả người sử dụng. Trong trường hợp đó khi chúng ta không sử dụng bộ nhớ cache thì mỗi cái sẽ truy cập vào cơ sở dữ liệu không cần thiết để tìm nạp dữ liệu. Ở mặt khác, như bạn có thể thấy, chúng tôi sử dụng bộ nhớ cache và trong trường hợp đó nếu có cùng một dữ liệu tĩnh và cùng một dữ liệu cho tất cả người dùng thì chỉ người dùng đầu tiên sẽ truy cập cơ sở dữ liệu và tìm nạp dữ liệu và lưu trữ vào bộ nhớ đệm và sau đó hai người dùng khác đã sử dụng nó từ bộ nhớ cache mà không cần nhấn cơ sở dữ liệu một cách không cần thiết để tìm nạp dữ liệu.
Về cơ bản, có hai loại bộ nhớ đệm .NET Core hỗ trợ
Khi chúng tôi sử dụng In-Memory Cache thì trong trường hợp đó, dữ liệu được lưu trữ trong bộ nhớ của máy chủ ứng dụng và bất cứ khi nào chúng tôi cần thì chúng tôi tìm nạp dữ liệu từ đó và sử dụng nó ở bất cứ đâu chúng tôi cần. Và trong Bộ đệm ẩn phân tán có nhiều cơ chế của bên thứ ba như Redis và nhiều cơ chế khác. Nhưng trong phần này, chúng ta xem xét chi tiết Redis Cache và cách nó hoạt động trong .NET Core
Redis là bộ nhớ đệm phổ biến nhất được nhiều công ty sử dụng hiện nay để cải thiện hiệu suất và khả năng mở rộng của ứng dụng. Vì vậy, chúng ta sẽ thảo luận về Redis và cách sử dụng từng cái một.
Bước 1
Tải xuống Máy chủ Redis bằng URL sau
https://github.com/microsoftarchive/redis/releases/tag/win-3.0.504
Bước 2
Giải nén tệp zip và sau đó mở Redis Server và Redis CLI
Bước 1
Tạo ứng dụng web .NET Core API
Bước 2
Cài đặt các Gói NuGet sau đây cần từng bước trong ứng dụng của chúng tôi
Bước 3
Tạo thư mục Model và tạo một Lớp Sản phẩm bên trong với các chi tiết
namespace RedisCacheDemo.Model
{
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public int Stock { get; set; }
}
}
Bước 4
Tiếp theo, Tạo Lớp DbContextClass cho các hoạt động liên quan đến Cơ sở dữ liệu như tôi đã trình bày bên dưới
using Microsoft.EntityFrameworkCore;
using RedisCacheDemo.Model;
namespace RedisCacheDemo.Data {
public class DbContextClass: DbContext {
public DbContextClass(DbContextOptions < DbContextClass > options): base(options) {}
public DbSet < Product > Products {
get;
set;
}
}
}
Bước 5
Bây giờ, chúng ta sẽ tạo Giao diện ICacheService và Lớp CacheService để sử dụng liên quan đến Redis Cache.
using System;
namespace RedisCacheDemo.Cache
{
public interface ICacheService
{
/// <summary>
/// Get Data using key
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
T GetData<T>(string key);
/// <summary>
/// Set Data with Value and Expiration Time of Key
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="expirationTime"></param>
/// <returns></returns>
bool SetData<T>(string key, T value, DateTimeOffset expirationTime);
/// <summary>
/// Remove Data
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
object RemoveData(string key);
}
}
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
namespace RedisCacheDemo.Cache {
public class CacheService: ICacheService {
private IDatabase _db;
public CacheService() {
ConfigureRedis();
}
private void ConfigureRedis() {
_db = ConnectionHelper.Connection.GetDatabase();
}
public T GetData < T > (string key) {
var value = _db.StringGet(key);
if (!string.IsNullOrEmpty(value)) {
return JsonConvert.DeserializeObject < T > (value);
}
return default;
}
public bool SetData < T > (string key, T value, DateTimeOffset expirationTime) {
TimeSpan expiryTime = expirationTime.DateTime.Subtract(DateTime.Now);
var isSet = _db.StringSet(key, JsonConvert.SerializeObject(value), expiryTime);
return isSet;
}
public object RemoveData(string key) {
bool _isKeyExist = _db.KeyExists(key);
if (_isKeyExist == true) {
return _db.KeyDelete(key);
}
return false;
}
}
}
Bước 6
Tạo lớp ProductController và tạo phương thức sau như hình dưới đây
using Microsoft.AspNetCore.Mvc;
using RedisCacheDemo.Cache;
using RedisCacheDemo.Data;
using RedisCacheDemo.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace RedisCacheDemo.Controllers {
[Route("api/[controller]")]
[ApiController]
public class ProductController: ControllerBase {
private readonly DbContextClass _dbContext;
private readonly ICacheService _cacheService;
public ProductController(DbContextClass dbContext, ICacheService cacheService) {
_dbContext = dbContext;
_cacheService = cacheService;
}
[HttpGet("products")]
public IEnumerable < Product > Get() {
var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
if (cacheData != null) {
return cacheData;
}
var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
cacheData = _dbContext.Products.ToList();
_cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime);
return cacheData;
}
[HttpGet("product")]
public Product Get(int id) {
Product filteredData;
var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
if (cacheData != null) {
filteredData = cacheData.Where(x => x.ProductId == id).FirstOrDefault();
return filteredData;
}
filteredData = _dbContext.Products.Where(x => x.ProductId == id).FirstOrDefault();
return filteredData;
}
[HttpPost("addproduct")]
public async Task < Product > Post(Product value) {
var obj = await _dbContext.Products.AddAsync(value);
_cacheService.RemoveData("product");
_dbContext.SaveChanges();
return obj.Entity;
}
[HttpPut("updateproduct")]
public void Put(Product product) {
_dbContext.Products.Update(product);
_cacheService.RemoveData("product");
_dbContext.SaveChanges();
}
[HttpDelete("deleteproduct")]
public void Delete(int Id) {
var filteredData = _dbContext.Products.Where(x => x.ProductId == Id).FirstOrDefault();
_dbContext.Remove(filteredData);
_cacheService.RemoveData("product");
_dbContext.SaveChanges();
}
}
}
Bước 7
Thêm chuỗi kết nối SQL Server và URL Redis bên trong appsetting.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"RedisURL": "127.0.0.1:6379",
"ConnectionStrings": {
"DefaultConnection": "Data Source=Server;Initial Catalog=RedisCache;User Id=sa;Password=***;"
}
}
Bước 8
Tiếp theo, Đăng ký ICacheService bên trong phương thức Cấu hình Dịch vụ của Lớp Khởi động và cũng thêm một số cấu hình liên quan đến Swagger để kiểm tra các điểm cuối API của chúng tôi
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using RedisCacheDemo.Cache;
using RedisCacheDemo.Data;
namespace RedisCacheDemo {
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration {
get;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
services.AddScoped < ICacheService, CacheService > ();
services.AddDbContext < DbContextClass > (options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new OpenApiInfo {
Title = "RedisCacheDemo", Version = "v1"
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "RedisCacheDemo v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
}
}
}
Bước 9
Tạo một lớp ConfigurationManger để định cấu hình cài đặt ứng dụng ở đó
using Microsoft.Extensions.Configuration;
using System.IO;
namespace RedisCacheDemo {
static class ConfigurationManager {
public static IConfiguration AppSetting {
get;
}
static ConfigurationManager() {
AppSetting = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
}
}
}
Bước 10
Tiếp theo, Tạo lớp trợ giúp kết nối cho Redis Connection
using StackExchange.Redis;
using System;
namespace RedisCacheDemo.Cache {
public class ConnectionHelper {
static ConnectionHelper() {
ConnectionHelper.lazyConnection = new Lazy < ConnectionMultiplexer > (() => {
return ConnectionMultiplexer.Connect(ConfigurationManager.AppSetting["RedisURL"]);
});
}
private static Lazy < ConnectionMultiplexer > lazyConnection;
public static ConnectionMultiplexer Connection {
get {
return lazyConnection.Value;
}
}
}
}
Bước 11
Thực hiện Di chuyển và Cập nhật Cơ sở dữ liệu cho Tạo DB bằng các lệnh sau trong Bảng điều khiển Trình quản lý Gói.
cơ sở dữ liệu cập nhật bổ sung "FirstMigration"
Vì vậy, khi bạn nhập và thực thi lệnh này, nó sẽ tạo ra một số thứ liên quan đến việc di chuyển và tạo cơ sở dữ liệu bên trong SQL Server khi bạn đặt bên trong Chuỗi kết nối trong appsetting.json
Bước 12
Cuối cùng, chạy ứng dụng và thêm dữ liệu bằng giao diện người dùng swagger và sau đó kiểm tra cách bộ nhớ đệm hoạt động bên trong sản phẩm và điểm cuối của sản phẩm.
Về cơ bản, tôi đã thêm bộ nhớ cache vào sản phẩm và các điểm cuối của sản phẩm trong bộ điều khiển, như bạn thấy khi người dùng muốn tìm nạp dữ liệu của tất cả các sản phẩm thì trước tiên, nó sẽ kiểm tra xem dữ liệu có bên trong Redis Cache hay không và nếu nó có bên trong sau đó bộ nhớ đệm trả lại dữ liệu đó cho người dùng và nếu dữ liệu không có bên trong bộ đệm, thì nó sẽ tìm nạp dữ liệu từ cơ sở dữ liệu và đồng thời, đặt dữ liệu đó vào bộ đệm. Vì vậy, lần sau người dùng sẽ chỉ nhận được điều đó từ bộ nhớ cache và tránh đánh vào cơ sở dữ liệu một cách không cần thiết
Ngoài ra, khi người dùng muốn tìm nạp dữ liệu từ bằng cách sử dụng id sản phẩm như bạn thấy trong bộ điều khiển ở điểm cuối thứ hai của sản phẩm, chúng tôi tìm nạp dữ liệu từ bộ nhớ cache của tất cả các sản phẩm, sau đó lọc bằng id sản phẩm và nếu điều đó xuất hiện thì trả về cho người dùng từ bộ nhớ cache và sau đó không tìm nạp từ cơ sở dữ liệu và trở lại người dùng sau khi áp dụng bộ lọc.
Vì vậy, như bạn thấy bên trong cập nhật, xóa và đăng điểm cuối của Bộ điều khiển sản phẩm, sau đó chúng tôi sử dụng phương pháp loại bỏ để xóa dữ liệu của khóa sản phẩm có bên trong bộ nhớ cache. Vì vậy, có rất nhiều tình huống và cách sử dụng bộ nhớ đệm mà bạn có thể sử dụng tùy theo nhu cầu và yêu cầu của mình. Tôi chỉ muốn giới thiệu những điều cơ bản về Redis Cache và cách nó hoạt động bên trong .NET Core mà tôi đã trình bày ở đây.
Ngoài ra, có một trường hợp bạn cần lưu ý khi sử dụng bộ nhớ đệm. Giả sử có hai người dùng sử dụng ứng dụng của bạn thì các trường hợp sau sẽ xảy ra.
Tạo đối tượng khóa riêng tư này trên đầu lớp
private static object _lock = new object()
Tiếp theo, sửa đổi phương thức Get như tôi đã hiển thị bên dưới
public IEnumerable < Product > Get() {
var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
if (cacheData != null) {
return cacheData;
}
lock(_lock) {
var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
cacheData = _dbContext.Products.ToList();
_cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime);
}
return cacheData;
}
Vì vậy, ở đây như bạn thấy, trước tiên, chúng tôi kiểm tra xem dữ liệu có bên trong bộ đệm hay không nếu dữ liệu có sẵn thì trả về. Tiếp theo, nếu giá trị không có trong bộ nhớ cache của Redis, thì chúng tôi áp dụng khóa ở đó và sau đó yêu cầu được khóa và nhập vào phần và tìm nạp chi tiết sản phẩm từ cơ sở dữ liệu, sau đó cũng đặt nó vào bộ nhớ cache và sau đó trả lại dữ liệu. Vì vậy, điều gì đã xảy ra khi người dùng thứ hai gửi yêu cầu trước khi yêu cầu của người dùng đó hoàn tất. Vì vậy, trong trường hợp đó, yêu cầu thứ hai nằm trong hàng đợi và sau khi hoàn thành yêu cầu người dùng đầu tiên, yêu cầu thứ hai xuất hiện trong hình
Ngoài ra, bạn có thể xem các chi tiết chính đã có bên trong Redis bằng Redis CLI như hình dưới đây
Vì vậy, ở đây bạn có thể thấy có nhiều lệnh cung cấp cho chúng tôi thông tin về các khóa có trong Redis Cache.
Đây là tất cả về Redis Cache trong .NET Core. Tôi hy vọng bạn hiểu những điều liên quan đến điều đó.
Chúc bạn mã hóa vui vẻ!
Nguồn: https://www.c-sharpcorner.com/article/implementation-of-the-redis-cache-in-the-net-core-api/
1655929080
Vamos discutir o cache no .NET Core e como ele funciona. Então, vamos olhar para as seguintes coisas, uma por uma.
Então, vamos começar um por um.
O armazenamento em cache é muito popular hoje em dia na indústria de software porque melhorará o desempenho e a escalabilidade do aplicativo. Usamos muitos aplicativos da web como Gmail e Facebook e vemos como eles são responsivos e temos uma ótima experiência do usuário. Há muitos usuários usando a internet e se um aplicativo tem grande tráfego de rede e demanda, precisamos cuidar de muitas coisas que nos ajudam a melhorar o desempenho e a capacidade de resposta do aplicativo. Então, por causa disso, existe a solução do cache e é por isso que o cache entra em cena.
O cache é o armazenamento de memória que é usado para armazenar os dados de acesso frequente no armazenamento temporário, melhorará drasticamente o desempenho e evitará o acesso desnecessário ao banco de dados e armazenará dados usados com frequência no buffer sempre que precisarmos.
Como você vê na imagem acima existem dois cenários, um é sem usar cache e outro é com cache. Então, aqui, quando não usamos o cache, nesse caso, suponha que os usuários desejam dados, eles acessarão cada vez o banco de dados e aumentará a complexidade do tempo e reduzirá o desempenho caso haja alguns dados estáticos que os usuários desejam e é o mesmo para todos os usuários. Nesse caso, quando não usamos o cache, cada um acessa o banco de dados desnecessário para buscar dados. Por outro lado, como você pode ver, usamos cache e, nesse caso, se houver a mesma estática e os mesmos dados para todos os usuários, apenas o primeiro usuário acessará o banco de dados e buscará os dados e os armazenará na memória cache e, em seguida, outros dois usuários usaram isso do cache sem acessar desnecessariamente o banco de dados para buscar dados.
Basicamente, existem dois tipos de suporte a cache do .NET Core
Quando usamos o In-Memory Cache, nesse caso, os dados são armazenados na memória do servidor de aplicativos e, sempre que precisamos, buscamos os dados e os usamos onde quer que precisemos. E no Distributed Caching existem muitos mecanismos de terceiros como Redis e muitos outros. Mas nesta seção, examinamos o Cache Redis em detalhes e como ele funciona no .NET Core
Redis é o cache mais popular usado por muitas empresas hoje em dia para melhorar o desempenho e a escalabilidade do aplicativo. Então, vamos discutir o Redis e o uso um por um.
Passo 1
Baixe o Redis Server usando o seguinte URL
https://github.com/microsoftarchive/redis/releases/tag/win-3.0.504
Passo 2
Extraia o arquivo zip e, posteriormente, abra o Redis Server e a Redis CLI
Passo 1
Criar o aplicativo Web da API do .NET Core
Passo 2
Instale os seguintes pacotes NuGet que precisam passo a passo em nosso aplicativo
etapa 3
Crie a pasta Model e crie uma classe de produto dentro dela com detalhes
namespace RedisCacheDemo.Model{ public class Product { public int ProductId { get; set; } public string ProductName { get; set; } public string ProductDescription { get; set; } public int Stock { get; set; } }}
Passo 4
Em seguida, crie a classe DbContextClass para operações relacionadas ao banco de dados como mostrei abaixo
using Microsoft.EntityFrameworkCore;using RedisCacheDemo.Model;namespace RedisCacheDemo.Data { public class DbContextClass: DbContext { public DbContextClass(DbContextOptions < DbContextClass > options): base(options) {} public DbSet < Product > Products { get; set; } }}
Etapa 5
Agora, vamos criar a Interface ICacheService e a Classe CacheService para uso relacionado ao Redis Cache.
using System;namespace RedisCacheDemo.Cache{ public interface ICacheService { /// <summary> /// Get Data using key /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> T GetData<T>(string key); /// <summary> /// Set Data with Value and Expiration Time of Key /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="value"></param> /// <param name="expirationTime"></param> /// <returns></returns> bool SetData<T>(string key, T value, DateTimeOffset expirationTime); /// <summary> /// Remove Data /// </summary> /// <param name="key"></param> /// <returns></returns> object RemoveData(string key); }}
using Newtonsoft.Json;using StackExchange.Redis;using System;namespace RedisCacheDemo.Cache { public class CacheService: ICacheService { private IDatabase _db; public CacheService() { ConfigureRedis(); } private void ConfigureRedis() { _db = ConnectionHelper.Connection.GetDatabase(); } public T GetData < T > (string key) { var value = _db.StringGet(key); if (!string.IsNullOrEmpty(value)) { return JsonConvert.DeserializeObject < T > (value); } return default; } public bool SetData < T > (string key, T value, DateTimeOffset expirationTime) { TimeSpan expiryTime = expirationTime.DateTime.Subtract(DateTime.Now); var isSet = _db.StringSet(key, JsonConvert.SerializeObject(value), expiryTime); return isSet; } public object RemoveData(string key) { bool _isKeyExist = _db.KeyExists(key); if (_isKeyExist == true) { return _db.KeyDelete(key); } return false; } }}
Etapa 6
Crie a classe ProductController e crie o seguinte método conforme mostrado abaixo
using Microsoft.AspNetCore.Mvc;using RedisCacheDemo.Cache;using RedisCacheDemo.Data;using RedisCacheDemo.Model;using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;namespace RedisCacheDemo.Controllers { [Route("api/[controller]")] [ApiController] public class ProductController: ControllerBase { private readonly DbContextClass _dbContext; private readonly ICacheService _cacheService; public ProductController(DbContextClass dbContext, ICacheService cacheService) { _dbContext = dbContext; _cacheService = cacheService; } [HttpGet("products")] public IEnumerable < Product > Get() { var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product"); if (cacheData != null) { return cacheData; } var expirationTime = DateTimeOffset.Now.AddMinutes(5.0); cacheData = _dbContext.Products.ToList(); _cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime); return cacheData; } [HttpGet("product")] public Product Get(int id) { Product filteredData; var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product"); if (cacheData != null) { filteredData = cacheData.Where(x => x.ProductId == id).FirstOrDefault(); return filteredData; } filteredData = _dbContext.Products.Where(x => x.ProductId == id).FirstOrDefault(); return filteredData; } [HttpPost("addproduct")] public async Task < Product > Post(Product value) { var obj = await _dbContext.Products.AddAsync(value); _cacheService.RemoveData("product"); _dbContext.SaveChanges(); return obj.Entity; } [HttpPut("updateproduct")] public void Put(Product product) { _dbContext.Products.Update(product); _cacheService.RemoveData("product"); _dbContext.SaveChanges(); } [HttpDelete("deleteproduct")] public void Delete(int Id) { var filteredData = _dbContext.Products.Where(x => x.ProductId == Id).FirstOrDefault(); _dbContext.Remove(filteredData); _cacheService.RemoveData("product"); _dbContext.SaveChanges(); } }}
Etapa 7
Adicione a string de conexão do SQL Server e a URL do Redis dentro de appsetting.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"RedisURL": "127.0.0.1:6379",
"ConnectionStrings": {
"DefaultConnection": "Data Source=Server;Initial Catalog=RedisCache;User Id=sa;Password=***;"
}
}
Etapa 8
Em seguida, registre o ICacheService dentro do método Configure Service da Startup Class e também adicione algumas configurações relacionadas ao Swagger para testar nossos endpoints da API
using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.OpenApi.Models;using RedisCacheDemo.Cache;using RedisCacheDemo.Data;namespace RedisCacheDemo { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddScoped < ICacheService, CacheService > (); services.AddDbContext < DbContextClass > (options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "RedisCacheDemo", Version = "v1" }); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "RedisCacheDemo v1")); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }}
Etapa 9
Crie uma classe ConfigurationManger para definir a configuração do aplicativo por lá
using Microsoft.Extensions.Configuration;using System.IO;namespace RedisCacheDemo { static class ConfigurationManager { public static IConfiguration AppSetting { get; } static ConfigurationManager() { AppSetting = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build(); } }}
Etapa 10
Em seguida, Criar classe auxiliar de conexão para conexão Redis
using StackExchange.Redis;using System;namespace RedisCacheDemo.Cache { public class ConnectionHelper { static ConnectionHelper() { ConnectionHelper.lazyConnection = new Lazy < ConnectionMultiplexer > (() => { return ConnectionMultiplexer.Connect(ConfigurationManager.AppSetting["RedisURL"]); }); } private static Lazy < ConnectionMultiplexer > lazyConnection; public static ConnectionMultiplexer Connection { get { return lazyConnection.Value; } } }}
Etapa 11
Execute migração e atualização de banco de dados para criação de banco de dados usando os comandos a seguir no console do gerenciador de pacotes.
add-migration "FirstMigration"
update-database
Portanto, quando você inserir e executar este comando, ele gerará algumas coisas relacionadas à migração e criará o banco de dados dentro do SQL Server conforme você coloca dentro da Connection String no appsetting.json
Etapa 12
Por fim, execute o aplicativo e adicione os dados usando a interface do usuário do swagger e, em seguida, verifique como o armazenamento em cache funciona nos produtos e no endpoint do produto.
Basicamente, adicionei cache nos endpoints do produto e produtos no controlador, como você vê quando o usuário deseja buscar dados de todos os produtos, primeiro ele verificará se os dados estão presentes dentro do Redis Cache ou não e se estão presentes dentro do cache, em seguida, retorna esses dados para o usuário e, se os dados não estiverem presentes dentro do cache, ele buscará os dados do banco de dados e também os definirá no cache. Então, da próxima vez, o usuário obterá isso apenas do cache e evitará acessar o banco de dados desnecessariamente
Além disso, quando o usuário deseja buscar dados usando o ID do produto como você vê no controlador no segundo endpoint do produto, buscamos dados do cache de todos os produtos e filtramos usando o ID do produto e, se isso for apresentado, retornamos ao usuário do cache e não buscar no banco de dados e retornar ao usuário após aplicar o filtro.
Então, como você vê dentro de update, delete e post endpoint do Product Controller, então usamos o método remove para remover os dados da chave do produto que está presente dentro do cache. Portanto, existem muitos cenários e uso de caches de memória que você pode usar de acordo com sua necessidade e requisitos. Eu só quero apresentar o básico do Redis Cache e como ele funciona dentro do .NET Core que abordei aqui.
Além disso, há um cenário que você precisa cuidar ao usar o cache. Suponha que haja dois usuários usando seu aplicativo, então os seguintes cenários acontecerão.
Crie este objeto privado de bloqueio no topo da classe
private static object _lock = new object()
Em seguida, modifique o método Get como mostrei abaixo
public IEnumerable < Product > Get() { var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product"); if (cacheData != null) { return cacheData; } lock(_lock) { var expirationTime = DateTimeOffset.Now.AddMinutes(5.0); cacheData = _dbContext.Products.ToList(); _cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime); } return cacheData;}
Então aqui, como você vê, primeiro, verificamos se os dados estão presentes dentro do cache ou não, se os dados estão disponíveis, então retornamos isso. Em seguida, se o valor não estiver presente no cache do Redis, aplicamos o bloqueio ali e, em seguida, a solicitação é bloqueada e inserida na seção e buscamos os detalhes do produto no banco de dados, e também definimos para o cache e, em seguida, retornar os dados. Então, o que aconteceu quando o segundo usuário envia uma solicitação antes que a solicitação do usuário seja concluída. Então, nesse caso, a segunda solicitação está na fila e depois de concluir a primeira solicitação do usuário, a segunda solicitação entra em cena
Além disso, você pode ver os principais detalhes que já estão presentes no Redis usando o Redis CLI, conforme mostrado abaixo
Então, aqui você pode ver que existem muitos comandos que nos fornecem informações sobre as chaves que estão presentes no Redis Cache.
Isso é tudo sobre o Redis Cache no .NET Core. Espero que você entenda as coisas relacionadas a isso.
Boa Codificação!
Fonte: https://www.c-sharpcorner.com/article/implementation-of-the-redis-cache-in-the-net-core-api/