iis服务器助手广告广告
返回顶部
首页 > 资讯 > 服务器 >ASP.NET如何使用SignalR2实现服务器广播
  • 773
分享到

ASP.NET如何使用SignalR2实现服务器广播

2023-06-30 17:06:30 773人浏览 薄情痞子
摘要

本篇内容介绍了“asp.net如何使用SignalR2实现服务器广播”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、概述这篇教程通过实现一

本篇内容介绍了“asp.net如何使用SignalR2实现服务器广播”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

    一、概述

    这篇教程通过实现一个股票报价的小程序来讲解如何使用SignalR进行服务器端的推送,服务器会模拟股票价格的波动,并把最新的股票价格推送给所有连接的客户端,最终的运行效果如下图所示。

    ASP.NET如何使用SignalR2实现服务器广播

    教程:使用 SignalR 2 广播的服务器

    可以通过Install-Package Microsoft.AspNet.SignalR.Sample来安装并查看完整的代码。

    二、服务器端代码

    新建一个名为Stock.cs的实体类,用来作为服务器端推送消息的载体,具体代码如下。

    这个实体类只有Symbol和Price这两个属性需要设置,其它属性将会依据Price自动进行计算。

    using System;namespace Microsoft.AspNet.SignalR.StockTicker{    public class Stock    {        private decimal _price;        public string Symbol { get; set; }        public decimal DayOpen { get; private set; }        public decimal DayLow { get; private set; }        public decimal DayHigh { get; private set; }        public decimal LastChange { get; private set; }        public decimal Price        {            get            {                return _price;            }            set            {                if (_price == value)                {                    return;                }                LastChange = value - _price;                _price = value;                if (DayOpen == 0)                {                    DayOpen = _price;                }                if (_price < DayLow || DayLow == 0)                {                    DayLow = _price;                }                if (_price > DayHigh)                {                    DayHigh = _price;                }            }        }        public decimal Change        {            get            {                return Price - DayOpen;            }        }        public double PercentChange        {            get            {                return (double)Math.Round(Change / Price, 4);            }        }    }}

    1、创建StockTicker和StockTickerHub类

    我们将使用SignalR Hub api来处理服务器到客户端的交互,所以新建一个继承自SignalR Hub类的StockTickerHub类来处理客户端的连接及调用。除此之外,我们还需要维护股票的价格数据以及新建一个Timer对象来定期的更新价格,而这些都与客户端连接无关的。由于Hub实例的生命周期很短暂,只有在比如客户端连接和调用的时候,Hub类实例是为Hub上的每个这样的操作才会创建新的实例,所以不要把与客户端连接及调用无关的代码放置到SignalR Hub类中。在这里,我们将维护股票数据、模拟更新股票价格以及向客户端推送股票价格的代码放置到一个名为StockTicker的类中。

    ASP.NET如何使用SignalR2实现服务器广播

    我们只需要在服务器端运行一个StockTicker类的实例(单例模式),由于这个StockTicker类维护着股票的价格,所以它也要能够将最新的股票价格推送给所有的客户端。为了达到这个目的,我们需要在这单个实例中引用所有的StockTickerHub实例,而这可以通过SignalR Hub的Context对象来获得,然后它可以使用SignalR连接Context对象向客户端广播。

    2、StockTickerHub类

    这个Hub类用来定义客户端可以调用的服务端方法,当客户端与服务器建立连接后,将会调用GetAllStocks()方法来获得股票数据以及当前的价格,因为这个方法是直接从内存中读取数据的,所以会立即返回IEnumerable数据。如果这个方法是通过其它可能会有延时的方式来调用最新的股票数据的话,比如从数据库查询,或者调用第三方的WEB Service,那么就需要指定Task>来作为返回值,从而实现异步通信,更多信息请参考ASP.net SignalR Hubs API Guide - Server - When to execute asynchronously。

    HubName属性指定了该Hub的别名,即客户端脚本调用的Hub名,如果不使用HubName属性指定别名的话,默认将会使用骆驼命名法,那么它在客户端调用的名称将会是stockTickerHub。

    using Microsoft.AspNet.SignalR.Hubs;using System.Collections.Generic;namespace Microsoft.AspNet.SignalR.StockTicker{    [HubName("stockTicker")]    public class StockTickerHub : Hub    {        private readonly StockTicker _stockTicker;        public StockTickerHub()            : this(StockTicker.Instance)        {        }        public StockTickerHub(StockTicker stockTicker)        {            _stockTicker = stockTicker;        }        public IEnumerable GetAllStocks()        {            return _stockTicker.GetAllStocks();        }    }}

    接下来我们将会创建StockTicker类,并且创建一个静态实例属性。这样不管有多少个客户端连接或者断开,内存中都只有一个StockTicker类的实例,并且还可以通过该实例的GetAllStocks方法来获得当前的股票数据。

    3、StockTicker类

    由于所有线程都运行 StockTicker 代码的同一个实例,StockTicker 类必须要是线程安全的。

    1、将单个实例保存在一个静态字段中

    在这个类中,我们新建了一个名为_instance的字段用来存放该类的实例,并且将构造函数的访问权限设置成私有状态,这样其它的类就只能通过Instance这个静态属性来获得该类的实例,而无法通过关键字new来创建一个新的实例。在这个_instance字段上面,我们使用了Lazy特性,虽然会损失一点儿性能,但是它却可以保证以线程安全的方式来创建实例。

    每次客户端连接到服务器时,运行在单独线程中的StockTickerHub类的新实例都会从StockTicker获取StockTicker单例实例。实例静态属性,如前面在StockTickerHub类中看到的。

    2、使用ConcurrentDictionary来存放股票数据

    这个类定义了一个_stocks字段来存放测试用的股票数据,并且通过GetAllStocks这个方法来进行获取。我们前面讲过客户端会通过StockTickerHub.GetAllStocks来获取当前的股票数据,其实就是这里的股票数据。

    在这个测试程序中,我们将数据存直接存放在内存中,这样做并没有什么问题,但在实际的应用场景中,则需要将数据存放在数据库之类的文件中以便长久的保存。

    3、定期的更新股票价格

    在这个类中,我们定义了一个Timer对象来定期的更新股票的价格。

    在实际的场景中,TryUpdateStockPrice方法通常会通过调用第三方的Web Service来获取最新的股票价格,而在这个程序中,我们则是通过随机数来进行模拟该实现。

    4、通过SignalR Hub的Context对象来实现服务端的推送

    因为股票价格变动是在StockTicker对象中,所以这个对象需要调用客户端的updateStockPrice回调方法来推送数据。在Hub类中,我们可以直接使用API来调用客户端的方法,但是这个StockTicker类并没有继承自Hub,所以无法直接使用这些对象。为了能够向客户端广播数据,StockTicker类需要使用SignalR Hub的Context对象来获得StokTickerHub类的实例,并用它来调用客户端的方法。

    using Microsoft.AspNet.SignalR.Hubs;using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.Threading;namespace Microsoft.AspNet.SignalR.StockTicker{    public class StockTicker    {        #region 字段        // 初始化StockTicker为单例实例        private readonly static Lazy _instance = new Lazy(() => new StockTicker(  GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients) );         //在创建StockTicker类静态实例的时候,把SignalR的Context引用通过构造函数传递给Clients这个属性。         //在这里只需要获取一次SignalR.Context,这样做有2个好处,首先是因为获取SignalR.Context很耗费资源,其次是获取一次SignalR.Context可以保留消息发送到客户端的预定义顺序。        private readonly object _marketStateLock = new object();        private readonly object _updateStockPricesLock = new object();        //为了线程安全,我们使用了ConcurrentDictionary来存放股票数据,当然你也可以使用Dictionary对象来进行存储,但是在更新数据之前需要进行定。        private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();        // 控制股票价格波动的百分比        private readonly double _rangePercent = 0.002;        private readonly TimeSpan _updateInterval = TimeSpan.FromMilliseconds(250);        private readonly Random _updateOrNotRandom = new Random();        private Timer _timer;        //使用volatile修饰符来标记_updatingStockPrices变量,该修饰符指示一个字段可以由多个同时执行的线程修改,声明为volatile的字段不受编译器优化(假定由单个线程访问)的限制,这样可以确保该字段在任何时间呈现的都是最新的值。        //该修饰符通常用于由多个线程访问但不使用lock语句对访问进行序列化的字段。        private volatile bool _updatingStockPrices;        #endregion 字段        #region 构造函数        private StockTicker(IHubConnectionContext<dynamic> clients)        {            Clients = clients;            _stocks.Clear();            var stocks = new List            {                new Stock { Symbol = "MSFT", Price = 41.68m },                new Stock { Symbol = "AAPL", Price = 92.08m },                new Stock { Symbol = "GoOG", Price = 543.01m }            };            stocks.ForEach(stock => _stocks.TryAdd(stock.Symbol, stock));            _timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);//定时更新股价        }        #endregion 构造函数        #region 属性        private IHubConnectionContext<dynamic> Clients { get; set; } //使用Clients属性,可以使您和在Hub类中一样,通过它来调用客户端的方法。        public static StockTicker Instance        {            get            {                return _instance.Value;            }        }        #endregion 属性        #region 方法        //获取所有股价        public IEnumerable GetAllStocks()        {            return _stocks.Values;        }        //在更新之前,我们使用了_updateStockPricesLock对象将需要更新的部份进行锁定,并通过_updatingStockPrices变量来确定是否有其它线程已经更新了股票的价格。        //然后通过对每一个股票代码执行TryUpdateStockPrice方法来确定是否更新股票价格以及股票价格的波动幅度。如果检测到股票价格变动,将会通过BroadcastStockPrice方法将最新的股票价格推送给每一个连接的客户端。        private void UpdateStockPrices(object state)        {            // 此函数必须可重入re-entrant,因为它是作为计时器间隔处理程序运行的。            lock (_updateStockPricesLock)            {                if (!_updatingStockPrices)                {                    _updatingStockPrices = true;                    foreach (var stock in _stocks.Values)                    {                        if (TryUpdateStockPrice(stock))                        {                            BroadcastStockPrice(stock);                        }                    }                    _updatingStockPrices = false;                }            }        }        private bool TryUpdateStockPrice(Stock stock)        {            // 随机选择是否更新该股票            var r = _updateOrNotRandom.NextDouble();            if (r > 0.1)            {                return false;            }            // 以范围百分比的随机因子更新股票价格            var random = new Random((int)Math.Floor(stock.Price));            var percentChange = random.NextDouble() * _rangePercent;            var pos = random.NextDouble() > 0.51;            var change = Math.Round(stock.Price * (decimal)percentChange, 2);            change = pos ? change : -change;            stock.Price += change;            return true;        }        private void BroadcastStockPrice(Stock stock)        {            Clients.All.updateStockPrice(stock); //Clients.All是dynamic类型的,意味着发送给所有的客户端,同时SignalR还提供了用来指定具体的客户端或组的属性,具体信息可以参考HubConnectionContext。        }        #endregion 方法    }}

    4、注册SignalR路由

    服务器需要知道把哪些请求交由SignalR进行操作,为了实现这个功能,我们需要在OWIN的Startup文件中进行相应的设置。

    using Owin;namespace Microsoft.AspNet.SignalR.StockTicker{    public static class Startup    {        public static void ConfigureSignalR(IAppBuilder app)        {            // For more infORMation on how to configure your application using OWIN startup, visit Http://go.microsoft.com/fwlink/?LinkID=316888            app.MapSignalR();        }    }}

    三、客户端代码

    StockTicker.html

    页面分别引入了Jquery、SignalR、SignalR代理,以及StockTicker脚本文件。SignalR代理文件(/signalr/hubs)将会根据服务器端编写的Hub文件动态的生成相应的脚本(生成关于StockTickerHub.GetAllStocks的相关代码),如果你愿意,你还可以通过SignalR Utilities来手动生成脚本文件,但是需要在MapHubs方法中禁用动态文件创建的功能。

    注意:请确保StockTicker.html文件中引入的脚本文件在你的项目中是实际存在的。

    <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head>    <title>ASP.NET SignalR Stock Ticker</title>    <link href="StockTicker.CSS" rel="external nofollow"  rel="stylesheet" /></head><body>    <h2>ASP.NET SignalR Stock Ticker Sample</h2>    <h3>Live Stock Table</h3>    <div id="stockTable">        <table border="1">            <thead>                <tr><th>Symbol</th><th>Price</th><th>Open</th><th>High</th><th>Low</th><th>Change</th><th>%</th></tr>            </thead>            <tbody>                <tr class="loading"><td colspan="7">loading...</td></tr>            </tbody>        </table>    </div>    <h3>Live Stock Ticker</h3>    <div id="stockTicker">        <div class="inner">            <ul>                <li class="loading">loading...</li>            </ul>         </div>    </div>    <script src="jquery-1.10.2.min.js"></script>    <script src="jquery.color-2.1.2.min.js"></script>    <script src="../Scripts/jquery.signalR-2.4.1.js"></script>    <script src="../signalr/hubs"></script>    <script src="SignalR.StockTicker.js"></script></body></html>

    StockTicker.js

    // Crockford's supplant method (poor man's templating)自定义的模板方法if (!String.prototype.supplant) {    String.prototype.supplant = function (o) {        return this.replace(/{([^{}]*)}/g,            function (a, b) {                var r = o[b];                return typeof r === 'string' || typeof r === 'number' ? r : a;            }        );    };}// A simple background color flash effect that uses jQuery Color pluginjQuery.fn.flash = function (color, duration) {    var current = this.css('backgroundColor');    this.animate({ backgroundColor: 'rgb(' + color + ')' }, duration / 2)        .animate({ backgroundColor: current }, duration / 2);};$(function () {    var ticker = $.connection.stockTicker, //$.connection即是指SignalR代理,这行代码表示将StockTickerHub类的代理的引用保存在变量ticker中,代理的名称即为服务器端通过[HubName]属性设置的名称。        up = '▲',        down = '▼',        $stockTable = $('#stockTable'),        $stockTableBody = $stockTable.find('tbody'),        rowTemplate = '{Symbol}{Price}{DayOpen}{DayHigh}{DayLow}{Direction} {Change}{PercentChange}',        $stockTicker = $('#stockTicker'),        $stockTickerUl = $stockTicker.find('ul'),        liTemplate = '{Symbol} {Price} {Direction} {Change} ({PercentChange})';    function formatStock(stock) {        return $.extend(stock, {            Price: stock.Price.toFixed(2),            PercentChange: (stock.PercentChange * 100).toFixed(2) + '%',            Direction: stock.Change === 0 ? '' : stock.Change >= 0 ? up : down,            DirectionClass: stock.Change === 0 ? 'even' : stock.Change >= 0 ? 'up' : 'down'        });    }    function scrollTicker() {        var w = $stockTickerUl.width();        $stockTickerUl.css({ marginLeft: w });        $stockTickerUl.animate({ marginLeft: -w }, 15000, 'linear', scrollTicker);    }    function stopTicker() {        $stockTickerUl.stop();    }    //init方法调用服务端的getAllStocks方法,并将返回的数据显示在Table中。服务端我们默认会使用帕斯卡命名法,而SignalR会在生成客户端的代理类时,自动将服务端的方法改成骆驼命名法,不过该规则只对方法名及Hub名称有效。    //而对于对象的属性名,则仍然和服务器端的一样,比如stock.Symbol、stock.Price,而不是stock.symbol、stock.price。    //如果你想在客户端使用与服务器商相同的名称(包括大小写),或者想自己定义其它的名称,那么你可以通过给Hub方法加上HubMethodName标签来实现这个功能,而HubName标签则可以实现自定义的Hub名称。    function init() {        return ticker.server.getAllStocks().done(function (stocks) {            $stockTableBody.empty();            $stockTickerUl.empty();            //遍历服务端返回的股票数据,然后通过调用formatStock来格式化成我们想要的格式,接着通过supplant方法(在StockTicker.js的最顶端)来生成一条新行,并把这个新行插入到表格里面。            $.each(stocks, function () {                var stock = formatStock(this);                $stockTableBody.append(rowTemplate.supplant(stock));                                 $stockTickerUl.append(liTemplate.supplant(stock));            });        });    }    //为了让服务器能够调用客户的代码,我们需要把updateStockPrice添加到stockTicker代理的client对象中    $.extend(ticker.client, {        updateStockPrice: function (stock) {            var displayStock = formatStock(stock),                $row = $(rowTemplate.supplant(displayStock)),                $li = $(liTemplate.supplant(displayStock)),                bg = stock.LastChange < 0                        ? '255,148,148' // red                        : '154,240,117'; // green            //该updateStockPrice方法和init方法一样,通过调用formatStock来格式化成我们想要的格式,接着通过supplant方法(在StockTicker.js的最顶端)来生成一条新行,不过它并不是将该新行追加到Table中,而是找到Table中现有的行,然后使用新行替换它。            $stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')                .replaceWith($row);            $stockTickerUl.find('li[data-symbol=' + stock.Symbol + ']')                .replaceWith($li);            $row.flash(bg, 1000);            $li.flash(bg, 1000);            scrollTicker();        }    });    // 客户端的代码编写好之后,就可以通过最后的这行代码来与服务器建立连接,由于这个start方法执行的是异步操作,并会返回一个jQuery延时对象,所以我们要使用jQuery.done函数来处理连接成功之后的操作。    //这个init方法其实是在start方法完成异步操作后作为回调函数执行的,如果你把init作为一个独立的javascript语句放在start方法之后的话,那么程序将会出错,因为这样会导致服务端的方法在客户端还没有与服务器建立连接之前就被调用。    $.connection.hub.start().done(init);});

    四、输出日志

    SignalR内置了日志功能,你可以在客户端选择开启该功能来帮助你调试程序,接下来我们将会通过开启SignalR的日志功能来展示一下在不同的环境下SignalR所使用的传输技术,大至总结如下:

    • websocket,至少需要IIS8及以上版本的支持。

    • Server-sent events,支持IE以外的浏览器。

    • Forever frame,支持IE浏览器。

    • ajax long polling,支持所有浏览器。

    在服务器端及客户端都支持的情况下,SignalR默认会选择最佳的传输方式。

    打开StockTicker.js,然后在客户端与服务端建立连接之前加上下面这段代码。

    // Start the connection$.connection.hub.logging = true;$.connection.hub.start().done(init);

    重新运行程序,并打开浏览器的开发工具,选择控制台标签,就可以看到SignalR输出的日志(如果想看到全部的日志,请刷新页面)。

    如果你是在windows 8(IIS 8)上用IE10打开的话,将会看到WebSocket的连接方式。

    ASP.NET如何使用SignalR2实现服务器广播

    如果你是在Windows 7(IIS 7.5)上用IE10打开的话,将会看到使用iframe的连接方式。

    ASP.NET如何使用SignalR2实现服务器广播

    Windows 8(IIS 8)上用Firefox的话,将会看到WebSocket的连接方式。

    ASP.NET如何使用SignalR2实现服务器广播

    在Windows 7(IIS 7.5)上用Firefox打开的话,将会看到使用Server-sent events的连接方式。

    ASP.NET如何使用SignalR2实现服务器广播

    “ASP.NET如何使用SignalR2实现服务器广播”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

    --结束END--

    本文标题: ASP.NET如何使用SignalR2实现服务器广播

    本文链接: https://www.lsjlt.com/news/330326.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • ASP.NET如何使用SignalR2实现服务器广播
      本篇内容介绍了“ASP.NET如何使用SignalR2实现服务器广播”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、概述这篇教程通过实现一...
      99+
      2023-06-30
    • ASP.NET使用SignalR2实现服务器广播
      目录一、概述二、服务器端代码1、创建StockTicker和StockTickerHub类2、StockTickerHub类3、StockTicker类1、将单个实例保存在一个静态字...
      99+
      2024-04-02
    • Java中xxl-job如何实现分片广播任务
      本篇内容介绍了“Java中xxl-job如何实现分片广播任务”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!xxl-job 是一个分布式任务调...
      99+
      2023-07-05
    • 怎么使用laravel-websockets实现广播系统
      本篇内容介绍了“怎么使用laravel-websockets实现广播系统”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!创建项目在 Apach...
      99+
      2023-07-04
    • 如何使用ionic播放轮询广告
      这篇文章主要介绍了如何使用ionic播放轮询广告,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。代码示例:<!DOCTYPE ...
      99+
      2024-04-02
    • 如何使用JavaScript实现轮播图
      这篇文章主要介绍了如何使用JavaScript实现轮播图,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。 wxml(使用官方的等等组件来展示...
      99+
      2024-04-02
    • ASP.NET Core如何使用AutoMapper实现实体映射
      这篇文章将为大家详细讲解有关ASP.NET Core如何使用AutoMapper实现实体映射,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、前言在实际的项目开发过程中,我们使用各种ORM框架可...
      99+
      2023-06-29
    • 如何使用asp.net实现ajax登录页面
      这篇文章将为大家详细讲解有关如何使用asp.net实现ajax登录页面,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。下面实现一个经典的登录页面,有保存密码功能,页面上所有...
      99+
      2024-04-02
    • BootStrap中jQuery插件Carousel如何实现轮播广告效果
      这篇文章将为大家详细讲解有关BootStrap中jQuery插件Carousel如何实现轮播广告效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。下图为最终效果:具体实现...
      99+
      2024-04-02
    • 如何使用vue实现轮播图片
      这篇“如何使用vue实现轮播图片”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“如何使用vue实现轮播图片”文章吧。效果图案例...
      99+
      2023-07-02
    • 如何使用html实现音乐播放
      小编给大家分享一下如何使用html实现音乐播放,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在html中可以使用“<audio>”标签定义声音,只需要...
      99+
      2023-06-07
    • ASP.NET Core通用主机如何实现托管服务
      本文小编为大家详细介绍“ASP.NET Core通用主机如何实现托管服务”,内容详细,步骤清晰,细节处理妥当,希望这篇“ASP.NET Core通用主机如何实现托管服务”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入...
      99+
      2023-07-02
    • 如何使用ASP.Net WebAPI构建REST服务
      这篇文章主要介绍了如何使用ASP.Net WebAPI构建REST服务的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何使用ASP.Net WebAPI构建REST服务文章都会有所收获,下面...
      99+
      2023-07-02
    • jquery如何实现轮播器
      这篇文章将为大家详细讲解有关jquery如何实现轮播器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。WEB开发经常实用到一种情况,即某个容器...
      99+
      2024-04-02
    • ASP.NET Core如何注入多个服务实现类
      目录1、定义个接口2、注入服务 3、功能类 4、高级类前言: 依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是...
      99+
      2024-04-02
    • asp.net Core中如何实现同名服务注册
      这篇文章主要为大家展示了“asp.net Core中如何实现同名服务注册”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“asp.net Core中如何实现同名服务注册”这篇文章...
      99+
      2023-06-29
    • 如何选择广东服务器租用
      选择广东服务器租用时,可以考虑以下几点: 服务商信誉和口碑:选择有良好信誉和口碑的服务商,可以保证服务质量和稳定性。 服务器性能:...
      99+
      2024-04-30
      服务器 广东服务器
    • Angular2 Service如何实现简单音乐播放器服务
      这篇文章给大家分享的是有关Angular2 Service如何实现简单音乐播放器服务的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。引言如果说组件系统(Component)是ng2...
      99+
      2024-04-02
    • Android ViewPager如何实现无限循环轮播广告位Banner效果
      这篇文章将为大家详细讲解有关Android ViewPager如何实现无限循环轮播广告位Banner效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。现在一些app通常会在头部放一个广告位,底部放置一行小...
      99+
      2023-05-30
      android viewpager banner
    • 如何使用uniapp vue与nvue实现轮播图
      小编给大家分享一下如何使用uniapp vue与nvue实现轮播图,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!vue部分如下:<template...
      99+
      2023-06-22
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作