c# 高级编程 32章827页 【创建Web API的客户端】

140 阅读1分钟
namespace BookServiceClientApp
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Client app, wait for service");
            Console.ReadLine();
            RegisterServices();
            var test = Container.GetRequiredService<SampleRequestClient>();
            
            await test.ReadChaptersAsync();
            await test.ReadChapterAsync();
            await test.ReadNotExistingChapterAsync();
            await test.ReadXmlAsync();
            await test.AddChapterAsync();
            await test.UpdateChapterAsync();
            await test.RemoveChapterAsync();
            Console.ReadLine();
        }

        public static void RegisterServices()
        {
            var services = new ServiceCollection();
            services.AddSingleton<UrlService>();
            services.AddSingleton<BookChapterClientService>();
            services.AddTransient<SampleRequestClient>();

            Container = services.BuildServiceProvider();
        }

        public static IServiceProvider Container { get; private set; }
    }
}

namespace BookServiceClientApp
{
    public class SampleRequestClient
    {
        private readonly UrlService _urlService;
        private readonly BookChapterClientService _client;
        public SampleRequestClient(UrlService urlService, BookChapterClientService client)
        {
            _urlService = urlService;
            _client = client;
        }

        public async Task ReadChaptersAsync()
        {
            Console.WriteLine(nameof(ReadChaptersAsync));
            IEnumerable<BookChapter> chapters = await _client.GetAllAsync(_urlService.BooksApi);
            foreach (BookChapter chapter in chapters)
            {
                Console.WriteLine(chapter.Title);
            }
            Console.WriteLine();
        }

        public async Task ReadChapterAsync()
        {
            Console.WriteLine(nameof(ReadChapterAsync));
            var chapters = await _client.GetAllAsync(_urlService.BooksApi);
            Guid id = chapters.First().Id;
            BookChapter chapter = await _client.GetAsync(_urlService.BooksApi + id);
            Console.WriteLine($"{chapter.Number} {chapter.Title}");
            Console.WriteLine();
        }

        public async Task ReadNotExistingChapterAsync()
        {
            Console.WriteLine(nameof(ReadNotExistingChapterAsync));
            string requestedIdentifier = Guid.NewGuid().ToString();
            try
            {
                BookChapter chapter = await _client.GetAsync(
                  _urlService.BooksApi + requestedIdentifier.ToString());
                Console.WriteLine($"{chapter.Number} {chapter.Title}");
            }
            catch (HttpRequestException ex) when (ex.Message.Contains("404"))
            {
                Console.WriteLine($"book chapter with the identifier " +
                  $"{requestedIdentifier} not found");
            }
            Console.WriteLine();
        }

        public async Task ReadXmlAsync()
        {
            Console.WriteLine(nameof(ReadXmlAsync));
            XElement chapters = await _client.GetAllXmlAsync(_urlService.BooksApi);
            Console.WriteLine(chapters);
            Console.WriteLine();
        }

        public async Task AddChapterAsync()
        {
            Console.WriteLine(nameof(AddChapterAsync));
            BookChapter chapter = new BookChapter
            {
                Number = 42,
                Title = "ASP.NET Web API",
                Pages = 35
            };
            chapter = await _client.PostAsync(_urlService.BooksApi, chapter);
            Console.WriteLine($"added chapter {chapter.Title} with id {chapter.Id}");
            Console.WriteLine();
        }

        public async Task UpdateChapterAsync()
        {
            Console.WriteLine(nameof(UpdateChapterAsync));
            var chapters = await _client.GetAllAsync(_urlService.BooksApi);
            var chapter = chapters.SingleOrDefault(c => c.Title == "Windows Store Apps");
            if (chapter != null)
            {
                chapter.Number = 32;
                chapter.Title = "Windows Apps";
                await _client.PutAsync(_urlService.BooksApi + chapter.Id, chapter);
                Console.WriteLine($"updated chapter {chapter.Title}");
            }
            Console.WriteLine();
        }

        public async Task RemoveChapterAsync()
        {
            Console.WriteLine(nameof(RemoveChapterAsync));
            var chapters = await _client.GetAllAsync(_urlService.BooksApi);
            var chapter = chapters.SingleOrDefault(c => c.Title == "ASP.NET Web Forms");
            if (chapter != null)
            {
                await _client.DeleteAsync(_urlService.BooksApi + chapter.Id);
                Console.WriteLine($"removed chapter {chapter.Title}");
            }
            Console.WriteLine();
        }
    }
}

namespace BookServiceClientApp.Services
{
    public class UrlService
    {
        public string BaseAddress => "http://localhost:1079/";
        public string BooksApi => "api/BookChapters/";
    }
}

namespace BookServiceClientApp.Services
{
    public abstract class HttpClientService<T> : IDisposable
      where T : class
    {
        private HttpClient _httpClient;
        private readonly UrlService _urlService;

        public HttpClientService(UrlService urlService)
        {
            _urlService = urlService;

            _httpClient = new HttpClient();
            _httpClient.BaseAddress = new Uri(_urlService.BaseAddress);
        }

        private async Task<string> GetInternalAsync(string requestUri)
        {
            if (_objectDisposed) throw new ObjectDisposedException(nameof(_httpClient));

            HttpResponseMessage resp = await _httpClient.GetAsync(requestUri);
            Console.WriteLine($"status from GET {resp.StatusCode}");
            resp.EnsureSuccessStatusCode();
            return await resp.Content.ReadAsStringAsync();
        }

        public async virtual Task<T> GetAsync(string requestUri)
        {
            string json = await GetInternalAsync(requestUri);
            return JsonConvert.DeserializeObject<T>(json);
        }

        public async virtual Task<IEnumerable<T>> GetAllAsync(string requestUri)
        {
            string json = await GetInternalAsync(requestUri);
            return JsonConvert.DeserializeObject<IEnumerable<T>>(json);
        }

        public async Task<XElement> GetAllXmlAsync(string requestUri)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(_urlService.BaseAddress);
                client.DefaultRequestHeaders.Accept.Add(
                  new MediaTypeWithQualityHeaderValue("application/xml"));
                HttpResponseMessage resp = await client.GetAsync(requestUri);
                Console.WriteLine($"status from GET {resp.StatusCode}");
                resp.EnsureSuccessStatusCode();
                string xml = await resp.Content.ReadAsStringAsync();
                XElement chapters = XElement.Parse(xml);
                return chapters;
            }
        }

        public async Task<T> PostAsync(string uri, T item)
        {
            if (_objectDisposed) throw new ObjectDisposedException(nameof(_httpClient));

            string json = JsonConvert.SerializeObject(item);
            HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
            HttpResponseMessage resp = await _httpClient.PostAsync(uri, content);
            Console.WriteLine($"status from POST {resp.StatusCode}");
            resp.EnsureSuccessStatusCode();
            Console.WriteLine($"added resource at {resp.Headers.Location}");
            json = await resp.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<T>(json);
        }

        public async Task PutAsync(string uri, T item)
        {
            if (_objectDisposed) throw new ObjectDisposedException(nameof(_httpClient));

            string json = JsonConvert.SerializeObject(item);
            HttpContent content = new StringContent(json, Encoding.UTF8,
              "application/json");
            HttpResponseMessage resp = await _httpClient.PutAsync(uri, content);
            Console.WriteLine($"status from PUT {resp.StatusCode}");
            resp.EnsureSuccessStatusCode();
        }

        public async Task DeleteAsync(string uri)
        {
            if (_objectDisposed) throw new ObjectDisposedException(nameof(_httpClient));

            HttpResponseMessage resp = await _httpClient.DeleteAsync(uri);
            Console.WriteLine($"status from DELETE {resp.StatusCode}");
            resp.EnsureSuccessStatusCode();
        }

        #region IDisposable Support
        private bool _objectDisposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!_objectDisposed)
            {
                if (disposing)
                {
                    _httpClient?.Dispose();
                }
                _objectDisposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
    }
}

namespace BookServiceClientApp.Services
{
    public class BookChapterClientService : HttpClientService<BookChapter>
    {
        public BookChapterClientService(UrlService urlService)
        : base(urlService) { }
        public override async Task<IEnumerable<BookChapter>> GetAllAsync(string requestUri)
        {
            IEnumerable<BookChapter> chapters = await base.GetAllAsync(requestUri);
            return chapters.OrderBy(c => c.Number);
        }
    }

}
namespace BookServiceClientApp.Models
{
    public class BookChapter
    {
        public Guid Id { get; set; }
        public int Number { get; set; }
        public string Title { get; set; }
        public int Pages { get; set; }
    }
}