ASP.NET Web API中展示實體Link相關的方面

来源:http://www.cnblogs.com/darrenji/archive/2016/01/20/5144162.html
-Advertisement-
Play Games

有時候,向服務端請求一個實體,我們希望返回如下的格式:links: [ href: http://localhost:8901/api/user/diaries/2013-08-17, rel: "self", method: "GET", isTemplated: false],currentDa...


 

有時候,向服務端請求一個實體,我們希望返回如下的格式:

 

links: [
    href: http://localhost:8901/api/user/diaries/2013-08-17,
    rel: "self",
    method: "GET",
    isTemplated: false
],
currentDate:"2013-08-17"

 

首先抽象出一個與Link相關的類:

 

public class LinkModel
{
    public stirng Href{get;set;}
    public stirng Rel{get;set;}
    public string Method{get;set;}
    public bool IsTemplated{get;set;}
}

 

再放到某個視圖模型中:

 

public class DiaryModel
{
    //存儲和模型相關的鏈接
    public ICollection<LinkModel> Links{get;set;}
    public DateTime CurrentDate{get;set;}
}

public class Diary
{
    public int Id{get;set;}
    public DateTime CurrentDate{get;set;}
}

 

ModelFactory用來實現視圖模型和領域模型之間的轉化。

 

public class ModelFactory
{

    private UrlHelper _urlHelper;
    
    public ModelFactory(HttpRequestMessage request)
    {
        _urlHelper = new UrlHelper(request);
    }
    
    //領域模型轉換成視圖模型
    public DiaryModel Create(Diary d)
    {
        return new DiaryModel()
        {
            Links = new List<LinkModel>
            {
                CreateLink(_urlHelper.Link("Diaryis", new {diaryid=d.CurrentDate.ToString("yyyy-MM-dd")}),"self");
            },
            CurrentDate = d.CurrentDate
        }
    }
    
    public LinkModel CreateLink(string href, string rel, string method = "GET", bool isTemplated = false)
    {
        return new LinkModel()
        {
            Href = href,
            Rel = rel,
            Method = method,
            IsTemplated = isTemplated
        }
    }
    
    //視圖模型轉換成領域模型
    public Diary Parse(DiaryModel model)
    {
        try
        {
            var entity = new Diary();
            var selfLink = model.Links.Where(l => l.Rel == "self").FirstOrDefault();
            
            if(selfLink != null && !string.IsNullOrWhiteSpace(selfLink.Href))
            {
                //從Uri中取出主鍵
                var uri = new Uri(selfLink.Href);
                entity.Id = int.Parse(uri.Segments.Last());
            }
            
            entity.CurrentDate = model.CurrentDate;
            
            return entity;
        }
        catch(Exception ex)
        {
        
        }
    }
}

 

Diaries這個controller略,路由方面:

 

//api/user/diaries
//api/user/diaries/2001-01-01
config.Routes.MapHttpRoute(
    name: "Diaries",
    routeTemplate: "api/user/diaries/{dairyid}",
    defaults: new {controller="diaries", diaryid=RouteParameter.Optional}
)

 

這樣,在客戶端發出 http://localhost:8901/api/user/diaries/2013-08-17 GET請求,得到如下的響應:

 

links: [
    href: http://localhost:8901/api/user/diaries/2013-08-17,
    rel: "self",
    method: "GET",
    isTemplated: false
],
currentDate:"2013-08-17"

在返回分頁相關的action中,也可以返回相關的Link部分。

先定義一個基類控制器:

 

public abstract class BaseController : ApiController
{
    ICountingKsRepository _repo;
    ModelFactory _modelFactory;
    
    public BaseController(ICountingKsRepository repo)
    {
        _repo = repo;
        //寫在構造函數里的話有點遲,必須等實例化_modelFactory才有值
        //_modelFactory = new ModelFactory(this.Request);
    }
    
    protected ModelFactory TheModelFactory
    {
        get
        {
            if(_modelFactory == null)
            {
                _modelFactory = new ModelFactory(this.Request, TheRepository);
            }
            return _modelFactory;
        }
    }
    
    protected ICountingsRepository TheRepoisitory
    {
        get
        {
            return _repo;
        }
    }
}

 

可見,把共同的部分封裝到基類控制器中是很好的習慣,然後基類控制器的子類通過屬性獲取一些方面。

再到具體的控制器:

 

public class FoodsController : BaseController
{
    ICountingKsRepoisotry _repo;
    ModelFactory _modelFactory;
    
    public FoodsController(ICountingKsRepository repo) : base(repo)
    {
    }
    
    const int PAGE_SIZE = 50;
    
    public object Get(bool includeMeasures = true, int page = 0)
    {
        IQueryable<Food> query;
        
        if(includeMeausres)
        {
            query = TheRepository.GetAllFoodsWithMeausres();
        }
        else
        {
            query = TheRepository.GetAllFoods();
        }
        
        //方便統計總數
        var baseQuery = query.OrderBy(f =>f.Description);
        
        //using System.Web.Http.Routing
        var helper = new UrlHelper(Request);
        
        var links = new List<LinkModel>();
        
        if(page > 0)
        {
            links.Add(TheModelFactory.CreateLink(helper.Link("Food", new {page = page - 1},"prevPage"));
        }
        
        if(page < totalPages - 1)
        {
            links.Add(TheModelFactory.CreateLink(helper.Link("Food", new {page = page + 1},"nextPage"));
        }
        
        //把上一頁和下一頁的url保存下來
        //var prevUrl = page > 0 ? helper.Link("Food", new {page = page - 1}) : "";
        //var nextUrl = page > 0 ? helper.Link("Food", new {page  = page + 1}) : "";
        
        //輸出總數
        var totalCount = baseQuery.Count();
        var totalPages = Math.Ceiling((double)totalCount/PAGE_SIZE);
        
        var result = baseQuery
                        .Skip(PAGE_SIZE * page)
                        .Take(PAGE_SIZE)
                        .ToList()
                        .Select(f => TheModelFactory.FoodFromDomainToView(f));
                        
        //方便客戶端接收
        return new
        {
            TotalCount = totalCount,
            TotalPages = totalPages,
            Result = result,
            Links = links
            //PrevPageUrl = prevUrl,
            //NextPageUrl = nextUrl,
        }
    }
    
    public FoodModel Get(int foodid)
    {
        return TheModelFactory.FoodFromDomainToView(TheRepository.GetFood(foodid));
    }
}

 

客戶端請求:localhost:8901/api/nutrition/foods

{
    totalCount:800,
    totalPages:151,
    links: [
        {
            href: http://localhost:8901/api/nutrition/foods?page=1,
            rel: "prevPage",
            method: "GET",
            isTemplated: false,
        },
        {
            href: http://localhost:8901/api/nutrition/foods?page=2,
            rel: "nextPage",
            method: "GET",
            isTemplated: false
        }
    ],
    result: [...]
}


另外,還可以控制序列化過程。

在LinkModel這個視圖中:

 

public class LinkModel
{
    public stirng Href{get;set;}
    public stirng Rel{get;set;}
    public string Method{get;set;}
    public bool IsTemplated{get;set;}
}

 

在顯示的時候,可能不想讓IsTemplated顯示出來,如何在序列化的過程中做到呢?

--通過jsonFormatter.SerializerSettings.Converts屬性,用來控制序列化為json數據時的顯示方式。

在WebApiConfig.cs中:

 

var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().FirstOrDefault();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNameContractResolver();
jsonFormatter.SerializerSettings.Converts(new LinkModelConverter());

 

而LinkModelConverter類需要繼承JsonConverter類。

 

public class LinkModelConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.Equals(typeof(LinkModel));
    }
    
    public override object ReadJson(JsonReader reader, Type object)
    {
        return reader.Value;
    }
    
    public override void WriteJson(JsonWriter wrtier, object value)
    {
        var model = value as LinkModel;
        if(model != null)
        {
            wirter.WriteStartObject();
            
            writer.WirteProeprtyName("href");
            writer.WriteValue(model.Href);
            
            writer.WriteProeprtyName("rel");
            writer.WriteValue(model.Rel);
            
            if(!model.Method.Equals("GET",StringComparison.ordinalIgnoreCase))
            {
                writer.WritePropertyName("method");
                writer.WriteValue(model.Method);
            }
            
            if(model.IsTemplated)
            {
                writer.WriterPropertyName("isTemplated");
                writer.WriteValue(model.IsTemplated);
            }
            
            writer.WriteEndObject();
        }
    }
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 作業要求:輸入用戶名,密碼認證成功顯示歡迎信息輸入錯誤三次後鎖定用戶Readme1.user_id.txt是存放用戶id及密碼的文件2.user_lock.txt是存放被鎖定的用戶id的文檔,預設為空.3.程式會對user_id.txt里的合法用戶id進行判斷,若連續輸入用戶id錯誤達三次程式直接退...
  • 今天,在用icinga伺服器端測試客戶端腳本時,報如下錯誤:[root@mysql-server1 etc]# /usr/local/icinga/libexec/check_nrpe -H 192.168.244.146 -c check_users -a 10 20CHECK_NRPE: Rec...
  • 一.概述 這裡以Linux為例。Linux歷史上,最開始使用的線程是LinuxThreads,但LinuxThreads有些方面受限於內核的特性,從而違背了SUSV3 Pthreads標準。即它要根據內核的特性來實現線程,有些地方沒有遵循統一的標準。後...
  • 1.Nginx的簡單說明 a. Nginx是一個高性能的HTTP和反向代理伺服器,也是一個IMAP/POP3/SMTP伺服器,期初開發的目的就是為了代理電子郵件伺服器室友:Igor Sysoev開發,源代碼符合BSD開源。其特點就是占用記憶體少併發能力強,在天朝使用Nginx的大型網站已經有很多:百....
  • 想來想去,還是得先寫一個程式,找下感覺,增強一下自信心,那就國際慣例Hello World吧。先到這個網址下一個Instant Contiki 2.7。之所以沒用3.0的,是因為有些問題,我源碼是下的3.0的。http://sourceforge.net/projects/contiki/files...
  • 昨天對公司資料庫進行備份。用了以下的方法一. 導出1、導出數據和表結構:mysqldump -u用戶名 -p密碼 資料庫名 > 資料庫名.sql或者切換到mysql目錄下:#/usr/local/mysql/bin/ mysqldump -uroot -p haier > haier.sql敲回車後...
  • using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace LambdaSample{ class Program { static void Mai...
  • 一般開發中會遇到很多需要自定義拋異常的情況,但是拋出的自定義異常又需要和其他異常(空值引用,數組越界,伺服器崩潰等)區分開,則可以用如下代碼簡單封裝。 public static void ThrowException(string exceptionMessage) { ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...