zoukankan      html  css  js  c++  java
  • 从零开始搭建Wpf基础7-Api数据接入

    前言:使用HttpClient获取Api数据。

    第一步:对获取数据结构进行规划,我们还是采用经典的Business作为中间层,HttpClient等底层请求数据的方法放在Service层。

    ViewModel -> Business -> Service

    第二步:HttpClient的使用httpClientFactory.CreateClient()来获取,避免端口号未能及时释放导致耗尽的情况,我们用单例来构造HttpClientHelper。

    public class HttpClientHelper
    {
        private static HttpClientHelper instance = null;
        private static object obj = new object();
        private IHttpClientFactory httpClientFactory;

        public static HttpClientHelper Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (obj)
                    {
                        if (instance == null)
                        {
                            instance = new HttpClientHelper();
                            var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();
                            instance.httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
                        }
                    }
                }
                return instance;
            }
        }      

        /// <summary>
        /// 记录日志
        /// </summary>
        public Action<string> HandleLog { get; set; }


        /// <summary>
        /// 使用post方法异步请求
        /// </summary>
        /// <param name="url">目标链接</param>
        /// <param name="json">发送的参数字符串,只能用json</param>
        /// <returns>返回的字符串</returns>
        public async Task<string> PostAsyncJson(string url, string json, Dictionary<string, string> header = null, TimeSpan? timeSpan = null)
        {
            HttpClient client = httpClientFactory.CreateClient();
            if (timeSpan.HasValue)
            {
                client.Timeout = timeSpan.Value;
            }
            HttpContent content = new StringContent(json);
            if (header != null)
            {
                client.DefaultRequestHeaders.Clear();
                foreach (var item in header)
                {
                    client.DefaultRequestHeaders.Add(item.Key, item.Value);
                }
            }
            content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

            string responseBody = string.Empty;
            string resData = string.Empty;
            DateTime startTime = DateTime.Now;

            try
            {
                HttpResponseMessage response = await client.PostAsync(url, content);
                response.EnsureSuccessStatusCode();
                responseBody = await response.Content.ReadAsStringAsync();
                resData = responseBody;
            }
            catch (Exception ex)
            {
                resData = $"异常:{ExceptionHelper.GetExceptionAllMsg(ex)}";

                throw ex;
            }
            finally
            {
                var time = DateTime.Now - startTime;
                if (resData?.Length > 1000)
                {
                    resData = resData.Substring(0, 1000);
                    resData += "......";
                }

                string log =
    $@"方向:请求外部接口
    url:{url}
    method:{"Post"}
    耗时:{(int)time.TotalMilliseconds}ms

    返回:{resData}
    ";
                HandleLog?.Invoke(log);
            }

            return responseBody;
        }


    }

    第三步:我们需要两个方法:一个登录的时候获取Token的方法(使用jwt登录校验,登录后服务返回一个密匙Token,客户端用这个Token去访问服务),一个Post请求数据的方法,如下:

    public class ApiDataProvider : IDataProvider
    {
        private string Url { get; set; }
        public string Token { get; set; }

        //携带Token
        public Dictionary<string, string> SetHeader()
        {
            Dictionary<string, string> header = new Dictionary<string, string>();
            header.Add("Authorization", string.Format("Bearer {0}", Token));

            return header;
        }

        //获取数据
        public async Task<AjaxResult<T>> GetData<T>(string url, string json = "{}")
        {
            if (!url.StartsWith("http"))
            {
                url = Url + url;
            }
            var content = await HttpClientHelper.Instance.PostAsyncJson(url, json, SetHeader());
            var result = JsonConvert.DeserializeObject<AjaxResult<T>>(content);
            return result;
        }

        //获取Token
        public async Task<AjaxResult> GetToken(string url, string userName, string password)
        {
            Url = url;

            var content = await HttpClientHelper.Instance.PostAsyncJson((string.Format("{0}/Base_Manage/Home/SubmitLogin", Url)), JsonConvert.SerializeObject(new { userName = userName, password = password }));
            var result = JsonConvert.DeserializeObject<AjaxResult>(content);
            Token = result.Data as string;

            return result;
        }

    }

    同样我们用接口实现,好处是方便随时切换数据获取方法,比如HttpClient换成了WebSocket、SignalR,使用GetToken和GetData的地方是不用动的,只要实现WebSocketDataProvider就行了。

    public interface IDataProvider
    {
        Task<AjaxResult> GetToken(string url, string userName, string password);


        //[LogHandler]
        Task<AjaxResult<T>> GetData<T>(string url, string json = "{}");
    }

    第四步:添加Core(有些也叫Util)工程,一些基础公共的方法和类放在这里,此处不在贴代码,暂时目录结构如下:

    第五步:修改登录页面LoginViewModel的逻辑,使用_dataProvider.GetToken来实现登录。

    IContainerExtension _container;
    IRegionManager _regionManager;
    IDataProvider _dataProvider;
    public LoginViewModel(IContainerExtension container, IRegionManager regionManager, IDataProvider dataProvider)
    {
        _container = container;
        _regionManager = regionManager;
        _dataProvider = dataProvider;

        Title = "Login";
    }
    private async void Login()
    {
        if (!string.IsNullOrEmpty(UserName)  && !string.IsNullOrEmpty(Password))
        {
            var mD5Password = Password.ToMD5String();
            var token = await _dataProvider.GetToken(ServerIP, UserName, mD5Password);
            if (!token.Success)
            {
                MessageBox.Show(token.Msg);
                return;
            }

            _regionManager.RequestNavigate("MainContentRegion", nameof(IntroduceView));

        }
        else
        {
            MessageBox.Show("请输入用户名或密码!");
        }


    }

    好了,运行看效果,很遗憾报错,因为IDataProvider并没有实现注册,程序并不知道IDataProvider是用ApiDataProvider实现的,当然你直接new一个也是可以的_dataProvider = new ApiDataProvider()。这就违背了我们IOC的初衷了。

    第六步:在App.xaml.cs中注册IDataProvider。

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.Register<IDataProvider, ApiDataProvider>();
    }

    再次运行,效果上还是一样的,但是我们成功的访问了后台。

    后续:下一章将实现,将登录界面做成独立窗口,登录后再显示主窗口。

    源码地址:https://gitee.com/akwkevin/aistudio.-wpf.-client.-stepby-step

    另外推荐一下我的Wpf客户端框架:https://gitee.com/akwkevin/aistudio.-wpf.-aclient

    作者:竹天笑
    互相学习,提高自己。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    关于 Blog 修改
    How To Manage StartUp Applications In Ubuntu
    C++11 之for 新解 auto
    How To Install Cacti On Ubuntu 14
    Apache 2 解析html中的php
    Raspberry Pi
    Compiling a kernel module for the raspberry pi 2 via Ubuntu host
    ubuntu 14.04/14.10 iptables 防火墙设置
    ajax概述
    ajax 异步 通信 小例子 servlet与 jsp异步 post方法
  • 原文地址:https://www.cnblogs.com/akwkevin/p/15130325.html
Copyright © 2011-2022 走看看