5

バックグラウンド

私たちのサイトには、次のような形式のリンクがいくつかあります。

http://oursite.com/books/c_sharp_in_depth_12345 .

これを処理するために、次の単純なプロパティを使用しますUrl

public class Book
{
    public string Url { get; set;}
}

基本的に、URL は、当社の Web サイトのドメイン、サイトのセクション (書籍など)、ページの名前、およびリソースを識別する一意の ID から取得されます。完全な URL がデータベースに保存されています。

データベースがセクション名を保存しているという事実は気に入りません。これは Web レイヤー プロパティのプロパティであり、本のプロパティではありません。データベースは、Web レイヤーに依存するべきではありません。

したがって、URL からセクションを削除すると、次のようになります。

public class Book
{
    public string UrlWithoutSection { get; set;}
}

OK、これはこの URL で機能します。しかし、当社の SEO 担当者は、私たちの URL が間違っていて、私たちの唯一無二の愛である Google が私たちを愛してくれるのは、私たちが次のように URL を書き直した場合だけだと言います。

http://oursite.com/programming-books/c-sharp-in-depth-12345

おっと、Web レイヤーへのデータベースの依存関係を削除したと思っていましたが、そうではありませんでした。結局のところ、セクションへの依存関係は削除されましたが、URL の形式はデータベースにまだ存在しています。URL をオブジェクトに抽象化することでこれを修正します。

public class OurUrl 
{
    public string title { get; set; }
    public string id { get; set; }
}

これで、Web レイヤーへの依存がなくなりました。ええと、今度は弊社の CEO が来ます。新しい会社を買収したばかりで、現在は雑誌を販売しています。すごい?雑誌の URL は次のようになります。

http://oursite.com/magazines/computers/stack-overflow-the-magazine/2012/01/01/12345

OK、問題ありません。別のオブジェクトを作成してください。

public class OurMagazineUrl : OurUrl
{
    public DateTime PublishedDate { get; set; }

    // Magazine enum will have to be created.
    public MagazineType Type { get; set; }  
} 

それは機能しますが、大きなサイトの計画があることに気づき始めます。たくさんの URL。さまざまな形式の URL がたくさんあります。毎回新しいクラスを作成することは、大きな頭痛の種のようです。

問題の概要

Web 層がビジネス層とデータ層から適切に分離されるように、URL をどのように処理しますか? 私は解決策についていくつかの考えを思いつきました:

問題の詳細

これがいくつかの混乱を明確にするのに役立つことを願っています。

ASP.Net MVC を使用しています。ルートを使用します。ヘルパーを使用します。ビジネス オブジェクトではなく、フラット化された DTO を Web レイヤーに渡します。この問題は、サービス層と DTO の急増に関係しています。

これは主にトラフィックの多いニュース サイトであり、ビジネス サイトではありません。多くの異なる URL を持つことができ、URL はいつでも変更できます。それらは複雑で、管理者によって任意に決定される可能性があります。

URL の例 (実際のものではありません。例として作成されています)。

 1. http://oursite.com/news/wi/politics/supreme-court/recent-ruling-someid
 2. http://oursite.com/news/wi/politics/election-2012/candidate-x-takes-stand-on-issue-y-someid
 3. http://oursite/com/news/politics/mayor-says-things-are-a-ok-someid
 4. http://oursite.com/news/milwaukee/local-bar-named-to-HOF-someid
 5. http://oursite.com/news/wi/politics/supreme-court-someid
 6. http://oursite.com/news/whatever-cat-our-CEO-wants/subcat1/subcat2/etc/2011/10/31/some-story-someid

上記はすべて「記事」であり、記事クラスがあります。記事には、AuthorObject、RelatedLinksCollection などの多数のナビゲーション プロパティがあります。ビジネス オブジェクトはクライアントに渡すには重すぎるため、情報を平坦化する DTO を渡します (AuthorName など)。ただし、上記のリンクは、すべて「記事」であっても、異なる情報を必要とする場合があります。

  1. カテゴリ、サブカテゴリ、タイトル、ID が必要
  2. Category、Subcategory、PoliticsCategory、タイトル、ID が必要
  3. カテゴリ、タイトル、ID が必要
  4. カテゴリ、タイトル、ID が必要
  5. カテゴリ、サブカテゴリ、タイトル、ID が必要
  6. CeoCategory、CeoSubcategory、PublishedDate、Title、ID が必要

C# などの静的プログラミング言語では、これを処理する通常の方法は、別個の DTO クラスを作成することです。継承を追加してコードの一部を削減することもできますが、それでも複数の「アーティクル」dto クラスが作成されます。

public class IArticleDto { 
  public string title { get; set; } 
  public string body { get; set; } 
  public string Category { get; set; }}

public class StateArticleDto: IArticleDto { 
  public string title { get; set; } 
  public string body { get; set; } 
  public string Category { get; set; }}
  public string StateCode { get; set; } 
  public string Subcategory { get; set; } 
}

public class SupremeCourtArticleDto: IArticleDto { 
  public string title { get; set; } 
  public string body { get; set; } 
  public string Category { get; set; }}
  public string Subcategory { get; set; } 
}

public class ArbitraryCeoArticleDto: IArticleDto { 
//who knows
}

交渉不可能な方法でカスタム URL を作成する機能。記事が何か (状態、カテゴリなど) に関連している場合、それは URL の一部になる可能性があります。

ソリューション?

  1. Url必要に応じてオブジェクトを追加し続けます。幾つか?少なくとも十数個ですが、名前を付けるのは面倒です。ビジネス オブジェクトごとに 1 つ実行すると、名前の問題は解決しますが、それは数十または数百の新しいオブジェクトを意味します。うん。

  2. IOC - 構成を介してルート パターンをデータ アクセス層に渡します。その後、データ アクセス レイヤーは完全な URL を作成できます。URL パターン名はまだ問題です。

  3. Dictionary<TKey, TValue>、などを使用KeyValuePair<TKey, TValue>して引き込みます。

  4. URL の詳細にはExpandoまたはを使用します。DynamicObjectしたがって、url にはいくつかの基本的なプロパティ (nameid) が含まれますが、必要に応じて他のプロパティを追加できます。

動的プログラミングが静的言語よりも優れていると思われるため、4) を使用することを考えています。ただし、私は新しいおもちゃで遊ぶのが好きなので、それを最も見ているだけかもしれません (私はこれまでに expando を使用したことがありません)。

オブジェクトの爆発のため、1)よりも優れています。2) が複雑なシナリオで機能するかどうかはわかりません。DI を使用して単純なルート名 + ルート情報をデータ層に渡すこともできますが、追加のゲインなしで達成するのは難しいようです。また、複雑なルートではおそらく機能しないでしょう。そのためには、UI 側にルール エンジンが必要だと思います。

3)に比べて、4)の方が少し良いと思います。私が間違っている場合は誰かが私を修正しますが、動的型は辞書の上にあるシンタックスシュガーにすぎないように見えますが、よりクリーンなコードという利点があります。ちょっとした考え。

4

4 に答える 4

2

率直に言って、あなたがこの質問をしているという事実と、あなたが提案している解決策に基づいているという事実は、目前の問題の鳥瞰的なアーキテクチャの見方をしていないということです. あなたのアプリケーションの詳細はわかりませんが、少し見通しを持ち、将来どのように使用されるかを想像することができると、URI の設計に役立ちます。

あなたが提案している解決策はすべて、非常に具体的でプログラム的な詳細を中心に展開していますが、問題は抽象的であり、プログラミングとはまったく関係ありません。問題を解決するには、ドメイン内のエンティティ、それらに対して実行可能なアクション、およびそれらが互いにどのように関係しているかを書き留めることがすべてです。

Bill de hÓra は、フレームワークの Web リソース マッピング基準に関するブログ投稿を行っています(これはキャッシュ バージョンです。実際のバージョンでも HTTP 500 エラーが発生する場合があります)。Joe Gregorio は、DayTrader を RESTify する方法について書いています。アプリケーションの完全な URI 空間を想定してください。計画、描画、思考、および執筆は、あなたとあなたのチームが行う必要があるように思えます。

アプリケーション内の URI の完全なスコープとスペースが設計されたら、それを実装する準備が整います。ただし、それはあなた次第です.URIテンプレートを使用してURI自体を定義し、通常のコードを使用してURIを処理するコードをマップすることをお勧めします(Controllers、Handlersなど)。ASP.NET MVC では、設定コードはRouteTableクラスに対して記述されますが、OpenRasta ではResourceSpaceクラスに対して行われます。

于 2011-10-30T21:15:29.740 に答える
0

外部DSLを維持できるステートマシンかもしれません。

Main
.*=Product
nj|ny=State
([a-z]*-)*=Title
20[1-9][1-9]->ExpectMonth =Year 
ExpectMonth
[0|1][0-9] = Month -> ExpectDay

など....

構造体コードを生成するための T4

struct Url {
 string Product {get;set}
 string State {get;set;}
}

「モノリシック クラス」のアンチパターンは、コード生成によって多少緩和されると思います。

于 2011-10-31T15:17:57.533 に答える
0

ドメイン エンティティ (書籍、雑誌など) を URL の認識から切り離す必要があることは理解できます。

本にアクセスするために必要な唯一の識別子(たとえば)は、そのId例では12345です。非 WWW チャネルに対して別の URI 構造が必要になる場合があるため、その他の分類要素はプレゼンテーション ロジックで処理する必要があります。そして、サイトを多言語で立ち上げたら?/magazines/computers/ をデータベースに永続化すると、障害になります。

SEO担当者の要件は、検索エンジンで上位にランク付けするためのテクニックも変化するため、時間の経過とともに変化する可能性があります.

そのため、これはURL ルーティングの問題です。

ASP.NET Webforms ソリューションでは、次のエントリを Global.asax ファイルに追加します。

void Application_Start(object sender, EventArgs e) 
{
    RegisterRoutes(System.Web.Routing.RouteTable.Routes);
}

public static void RegisterRoutes(System.Web.Routing.RouteCollection routes)
{
    routes.MapPageRoute("Book",
        "{productType}/{categoryName}/{productName}/{productId}",
        "~/Books.aspx");

    routes.MapPageRoute("Magazine",
        "{productType}/{categoryName}/{productName}/{year}/{month}/{day}/{productId}",
        "~/Magazines.aspx");
}

Books.aspx と Magazines.aspx は、URL の関連部分を次のように収集します。

var categoryName = Page.RouteData.Values["categoryName"];

表示する製品を一意に識別するのに十分な情報を収集したら、ドメイン/データ層にクエリを実行して、必要な情報を取得できます。

新しい製品タイプが利用可能になった場合 (または利害関係者から新しい URL 構造が要求された場合)、別のルートを追加するだけで済みます。

于 2011-10-30T21:12:41.167 に答える
0

これが私の最初の#4です。それは機能し、動的オブジェクト タイプはエレガントに機能します。

public class ArticleDto 
{
//normal Article properties
//code goes here

//new dyamic property for the Uri Details
public dynamic UriDetails { get; set; }
}

次に、URI の詳細を処理するカスタム クラスを作成しました。リソース名 + id を常に例外なく渡す必要があるため、名前 + id のコンストラクターを追加しました。

public class UriDetails : DynamicObject
{
    //TODO put error handling in here to ensure that they're not empty?
    public string ResourceName { get; set; }
    public int ResourceId { get; set; }

    public UriDetails(int resourceId, string resourceName)
    {
        ResourceId = resourceId;
        ResourceName = resourceName;
    }
//other code that you need to override
}

次に、私の DataAccess コードで

ArticleDto = new ArticleDto();
//Set the regular properties
//code goes here

//Set the mandatory uri properties
ArticleDto.UriDetails = new UriDetails(id, articleTitle);

//Set any other properties specific to this call
ArticleDto.Date = publishedDate;

1 つの注意点: これによりサービス レイヤーの問題は解決されますが、Web レイヤーは URL の作成方法を知る必要があります。これは、UriDetails のプロパティ名と型に基づいて使用されるものを決定する、ある種のヘルパー クラス/ルール エンジンになります。

どう考えているか教えてください。

于 2011-10-31T16:27:40.460 に答える