• GraphQL教程(四) .net core api


    今天学个比较难的——订阅
    订阅功能:运行后,打开两个浏览器,同样在GraphQL界面上操作。其中一个开启监听,另一个创建,用MovicRating事件将两者关联,创建成功后,监听的界面也将显示相关消息。
    总共有五个步骤
    1.在Movie文件夹创建事件属性MovieEvent,类型MovieEventType
    2.在Service文件夹创建接口IMovieEventService与实现接口MovieEventService类
    3.修改MovieSerivce类的创建程序,在其中添加事件
    4.Schema文件夹实现订阅方法MovieSubscription类
    5.将MovieSubscription添加到MovieSchema类,并到startup类注册相关服务

    1.在Movie文件夹创建事件属性MovieEvent,类型MovieEventType

    MovieEvent类

    using System;
    
    namespace GraphStudy.Movies.Movies
    {
        public class MovieEvent
        {
            public MovieEvent()
            {
                //初始化系统的一个新实例。Guid结构。
                Id = Guid.NewGuid();
            }
            public Guid Id { get; set; }
            public int MovieId { get; set; }
            public string Name { get; set; }
            public DateTime TimeStamp { get; set; }
            public MovieRating MovieRating { get; set; }
        }
    }
    

    这个是与事件触发相关的类,并不是Movie类的那种格式了

    Guid解释:GUID(全局统一标识符)是指在一台机器上生成的数字,
    它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成GUID的API。
    生成算法很有意思,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。
    GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”
    GUID的唯一缺陷在于生成的结果串会比较大。”

    MovieEventType类

    using GraphQL.Types;
    using GraphStudy.Movies.Movies;
    
    namespace GraphStudy.Movies.Schema
    {
        public class MovieEventType:ObjectGraphType<MovieEvent>
        {
            public MovieEventType()
            {
                Name = "MovieEventType";
    
                Field(x => x.Id, type: typeof(IdGraphType));//guid有点特殊
                Field(x => x.Name);
                Field(x => x.MovieId);
                Field(x => x.TimeStamp);
                Field(x => x.MovieRating, type: typeof(MovieRatingEnum));
            }
        }
    }
    
    

    这个还是老样子,不过要注意有些特殊类型要额外提出来,不然运行会出错

    2.在Service文件夹创建接口IMovieEventService与实现接口MovieEventService类

    IMovieEventService类

    using GraphStudy.Movies.Movies;
    using System;
    using System.Collections.Concurrent;
    
    namespace GraphStudy.Movies.Services
    {
        //Service发布事件,客户端可以接受这个时间的通知
        public interface IMovieEventService
        {
            //首先需要个合集,ConcurrentStack为并发集合,与线程相关
            ConcurrentStack<MovieEvent> AllEvent { get; }
    
            //添加异常的方法
            void AddError(Exception ex);
    
            //添加MovieEvent方法
            MovieEvent AddEvent(MovieEvent e);
    
            //定义stream方法
            IObservable<MovieEvent> EventStream();
    
            //c#中的Observer和IObservable用于观察者与事件、代理
        }
    }
    
    

    MovieEventService类

    using GraphStudy.Movies.Movies;
    using System;
    using System.Collections.Concurrent;
    using System.Reactive.Linq;
    using System.Reactive.Subjects;
    
    namespace GraphStudy.Movies.Services
    {
        public class MovieEventService : IMovieEventService
        {
            //ISubject:表示既是可观察序列又是观察者的对象。
            //ReplaySubject意思为无论订阅者什么时候订阅都会将以前发布的内容发布给他,并初始化ISubject对象
            private readonly ISubject<MovieEvent> _eventStream=new ReplaySubject<MovieEvent>();
    
            //ConcurrentStack:后进的线程后出
            public ConcurrentStack<MovieEvent> AllEvent { get; }
    
            public MovieEventService()
            {
                AllEvent=new ConcurrentStack<MovieEvent>();
            }
    
            public void AddError(Exception ex)
            {
                _eventStream.OnError(ex);
            }
    
            public MovieEvent AddEvent(MovieEvent e)
            {
                //Push推送
                AllEvent.Push(e);
                //OnNext:当前消息通知
                _eventStream.OnNext(e);
                return e;
            }
    
            //IObservable<T>:通知程序观察者将接到消息通知
            //T:代表观察员,接收通知对象
            public IObservable<MovieEvent> EventStream()
            {
                //AsObservable:隐藏源序列身份的可观察序列
                return _eventStream.AsObservable();
            }
        }
    }
    

    3.修改MovieSerivce类的创建程序,在其中添加事件

    using GraphStudy.Movies.Movies;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace GraphStudy.Movies.Services
    {
        public class MovieService : IMovieService
        {
            //因为我们需要创建子列表,所以一要用到IList
            private readonly IList<Movie> _movie;
            private readonly IMovieEventService _movieEventService;
    
            public MovieService(IMovieEventService movieEventService)
            {
                _movieEventService = movieEventService;
    
                _movie=new List<Movie>
                {
                    #region 电影列表
        
                    new Movie
                    {
                        Id = 1,
                        Name = "肖申克的救赎The Shawshank Redemption",
                        Company = "美国",
                        MovieRating = MovieRating.G,
                        ActorId = 1,
                        ReleaseDate = new DateTime(1994-10-14)
                    },
                    new Movie
                    {
                        Id = 2,
                        Name = "这个杀手不太冷 Léon ",
                        Company = "法国",
                        MovieRating = MovieRating.NC17,
                        ActorId = 2,
                        ReleaseDate = new DateTime(1994-09-14)
                    },
                    new Movie
                    {
                        Id = 3,
                        Name = "三傻大闹好莱坞",
                        Company = "印度",
                        MovieRating = MovieRating.PG,
                        ActorId = 3,
                        ReleaseDate = new DateTime(2011-12-08)
                    },
                    new Movie
                    {
                        Id = 4,
                        Name = "功夫",
                        Company = "美国",
                        MovieRating = MovieRating.G,
                        ActorId = 4,
                        ReleaseDate = new DateTime(2004-12-23)
                    }
                    #endregion
                };
            }
    
    
            public Task<Movie> CreateAsync(Movie movie)
            {
                _movie.Add(movie);
    
                //创建时发布事件
                var movieEvent = new MovieEvent
                {
                    Name = $"Add Movie",
                    MovieId = movie.Id,
                    MovieRating = movie.MovieRating,
                    TimeStamp = DateTime.Now
                };
                _movieEventService.AddEvent(movieEvent);
    
                return Task.FromResult(movie);
            }
    
            public Task<IEnumerable<Movie>> GetAsyncs()
            {
                return Task.FromResult(_movie.AsEnumerable());
            }
    
            public Task<Movie> GetByIdAsync(int id)
            {
                //在这里需要做个判断这个id是否存在
                var movie = _movie.SingleOrDefault(x => x.Id == id);
                if (movie == null)
                {
                    throw new ArgumentException(String.Format("Movie ID {0} 不正确", id));
                }
    
                return Task.FromResult(movie);
            }
        }
    }
    
    

    修改了两个地方,可自行上下代码对照

    //第一个
    private readonly IMovieEventService _movieEventService;
    public MovieService(IMovieEventService movieEventService)
    
    //第二个
    public Task<Movie> CreateAsync(Movie movie)
            {
                _movie.Add(movie);
    
                //创建时发布事件
                var movieEvent = new MovieEvent
                {
                    Name = $"Add Movie",
                    MovieId = movie.Id,
                    MovieRating = movie.MovieRating,
                    TimeStamp = DateTime.Now
                };
                _movieEventService.AddEvent(movieEvent);
    
    

    看不懂没关系,多抄几遍,炒得多了,慢慢就懂了

    4.Schema文件夹实现订阅方法MovieSubscription类

    using GraphQL.Resolvers;
    using GraphQL.Subscription;
    using GraphQL.Types;
    using GraphStudy.Movies.Movies;
    using GraphStudy.Movies.Services;
    
    namespace GraphStudy.Movies.Schema
    {
        public class MovieSubscription:ObjectGraphType
        {
            private readonly IMovieEventService _movieEventService;
    
            public MovieSubscription(IMovieEventService movieEventService)
            {
                _movieEventService = movieEventService;
                Name = "Subscription";
    
                //这里注意。以前的field不管用,EventStreamFieldType为AddField的参数
                AddField(new EventStreamFieldType
                {
                    Name = "movieEvent",
                    //Arguments给AddField添加参数
                    Arguments = new QueryArguments(new QueryArgument<ListGraphType<MovieRatingEnum>>
                    {
                        Name = "movieRatings"
                    }),
                    Type = typeof(MovieEventType),//这里的类型与GraphQL文档里的类型相对应
                    Resolver = new FuncFieldResolver<MovieEvent>(ResolveEvent),//传递ResolveEvent方法
                    Subscriber = new EventStreamResolver<MovieEvent>(Subscribe)//传递Subscribe方法
                });
    
            }
    
            private MovieEvent ResolveEvent(ResolveFieldContext context)
            {
                var movieEvent = context.Source as MovieEvent;
                return movieEvent;
            }
    
            private IObservable<MovieEvent> Subscribe(ResolveEventStreamContext context)
            {
                //取得枚举的集合,这里的name应与上面的Arguments的name对应,new List<MovieRating>()给其默认值。空值
                var ratingList = context.GetArgument<IList<MovieRating>>("movieRatings", new List<MovieRating>());
    
                //if为过滤操作,any()确定ratingList是否含有元素
                if (ratingList.Any())
                {
                    MovieRating ratings = 0;
                    foreach (var rating in ratingList)
                    {
                        ratings = rating;
                    }
    
                    return _movieEventService.EventStream().Where(e => (e.MovieRating & ratings) == e.MovieRating);
                }
                else
                {
                    return _movieEventService.EventStream();
                }
            }
     
        }
    }
    
    

    有些复杂,抄过去就是了,回头多抄几遍

    5.将MovieSubscription添加到MovieSchema类,并到startup类注册相关服务

    MovieSchema类

    using GraphQL;
    
    namespace GraphStudy.Movies.Schema
    {
        public class MovieSchema:GraphQL.Types.Schema
        {
            public MovieSchema(IDependencyResolver dependencyResolver, 
                MoviesQuery moviesQuery,
                MoviesMutation moviesMutation,
                MovieSubscription movieSubscription)
            {
                DependencyResolver = dependencyResolver;
                Query = moviesQuery;
                Mutation = moviesMutation;
                Subscription = movieSubscription;
            }
        }
    }
    
    

    startup类注册

    		services.AddSingleton<MovieEventType>();
                services.AddSingleton<IMovieEventService, MovieEventService>();
                services.AddSingleton<MovieSubscription>();
    

    怎么注册就不用多说了吧

    最后查看订阅
    在这里插入图片描述
    先点击右边两个,进入监听模式
    后点击左边那个create,创建
    然后你发现右下边那张图出现了下面那张图的情况,另一个依旧在监听模式
    在这里插入图片描述

    好了,今天的订阅模式搞定了,多回去敲敲

  • 相关阅读:
    DataGridView中DataGridViewComDaboBoxColumn控件点击一次即可显示下拉菜单
    Django2.X报错-------ModuleNotFoundError: No module named 'django.core.urlresolvers'
    C#控件——批量化隐藏或显示同类型控件
    Python——Django运行问题
    关于VS2010 在设计窗口时控件消失问题
    DataGridView操作小记(1)
    c#_生成图片式验证码
    日常杂记——C#验证码
    DataGridView添加的数据最后一步无法生效的问题。
    request.getRequestDispatcher().forward(request,response)和response.sendRedirect()的区别
  • 原文地址:https://www.cnblogs.com/zuiren/p/10849932.html
Copyright © 2020-2023  润新知