2009-10-18 41 views
5

Đây là câu hỏi đầu tiên:Tự động tạo một AppSettings lớp mạnh mẽ-gõ

Đây có phải là có thể? Tôi lấy cảm hứng từ Joe Wrobel's work (một sự lãng quên của sự lãng quên Codeplex project). Ở đây, bạn thực hiện công việc của mình trong việc tạo hồ sơ cho nhà cung cấp, và nó thực hiện công việc tạo ra sự đánh máy mạnh mẽ cho nó, tạo ra một mặt tiền cho lớp Profile một cách hiệu quả.

Và giờ là câu chuyện sau!

Tôi thực sự không thích magic strings. Chúng khá tệ và có thể gây ra một số vấn đề nghiêm trọng khi cập nhật ứng dụng của bạn. Đã từng làm việc trong các ngôn ngữ như PHP và ColdFusion, tôi biết rằng việc đặt chúng vào ứng dụng của bạn thật dễ dàng và quên chúng đi cho đến khi bạn cần thay đổi. Và sau đó bạn phải săn lùng từng biến thể của chúng và thay đổi chúng cho phù hợp.

.NET thực sự không tốt hơn nhiều nếu bạn làm theo mẫu ứng dụng 'ngoài hộp'. Rất nhiều ví dụ hiện có sử dụng các ứng dụng trong web.config để lưu trữ các cài đặt khác nhau. Đây thực sự là một nơi tốt để lưu trữ và hoàn hảo cho hầu hết các ứng dụng. Tuy nhiên, vấn đề bắt đầu phát sinh, khi bạn bắt đầu gọi trực tiếp những vấn đề này - ví dụ: ConfigurationManager.AppSettings["MyAppSetting"]. Sau đó, bạn không thực sự tốt hơn so với một người sử dụng PHP khi bạn trở lại sử dụng dây ma thuật.

Đây là nơi facades tham gia. Mặt tiền cung cấp cách tạo đối tượng được nhập mạnh từ chuỗi ma thuật ở một nơi và tham chiếu nhà phát triển từ phần còn lại của ứng dụng.

Bây giờ, thay vì sử dụng web.config để chứa các ứng dụng của tôi, tôi sử dụng cơ sở dữ liệu để giữ tất cả. Khi bắt đầu ứng dụng, các combo tên/giá trị được lấy ra, và sau đó được thêm vào một cách tuần tự vào ConfigurationManager.AppSettings qua Set. Không có biggie (ngoài số problem Tôi đã có trước đó!).

Lớp mặt ứng dụng này có thể truy cập bởi lớp dữ liệu, lớp dịch vụ và lớp trình bày và giữ những thứ như chế độ ứng dụng, dịch vụ nào sẽ sử dụng yada yada yada và hạn chế nhu cầu tìm kiếm nhiều chuỗi ma thuật, xuống đến hai chuỗi ma thuật - một (tên) ở mặt tiền, và cái kia (tên và giá trị) ở điểm tạo ra (trong đó, đối với tôi là db).

Lớp mặt tiền này cuối cùng sẽ nhận được khá lớn và cuối cùng tôi sẽ cảm thấy mệt mỏi vì phải cập nhật cả hai.

Vì vậy, những gì tôi muốn làm là có một lớp ApplicationFacade tự động tạo ra mỗi khi xây dựng xong. Và bây giờ quay lại đầu ... Liệu điều này có thể?

Trả lời

7

Bạn cũng có thể sử dụng mẫu CodeSmith cho mục đích này.Lợi thế là bạn có thể đặt trong thuộc tính tệp mẫu được tạo lại trên mỗi bản dựng (thiết lập BuildAction = "Complile")

Đã chỉnh sửa Tôi cũng tìm giải pháp như vậy. Sau khi googling tôi tìm thấy mẫu T4 cơ sở để tạo ra một lớp như vậy. Tôi đã thiết kế lại nó và bạn có thể tìm thấy nó bên dưới.

Template được tạo ra lớp wrapper cho phần appSetting từ Web.config/App.config nộp

Giả sử bạn đã thiết lập dòng trong tập tin cấu hình

<appSettings> 
    <add key="PageSize" value="20" /> 
    <add key="CurrentTheme" value="MyFavouriteTheme" /> 
    <add key="IsShowSomething" value="True" /> 
    </appSettings> 

sau Sau khi xử lý mẫu mà bạn sẽ nhận được sau lớp

namespace MyProject.Core 
{ 
    /// <remarks> 
    /// You can create partial class with the same name in another file to add custom properties 
    /// </remarks> 
    public static partial class SiteSettings 
    { 
     /// <summary> 
     /// Static constructor to initialize properties 
     /// </summary> 
     static SiteSettings() 
     { 
      var settings = System.Configuration.ConfigurationManager.AppSettings; 
      PageSize = Convert.ToInt32(settings["PageSize"]); 
      CurrentTheme = (settings["CurrentTheme"]); 
      IsShowSomething = Convert.ToBoolean(settings["IsShowSomething"]); 
     } 

     /// <summary> 
     /// PageSize configuration value 
     /// </summary> 
     public static readonly int PageSize; 

     /// <summary> 
     /// CurrentTheme configuration value 
     /// </summary> 
     public static readonly string CurrentTheme; 

     /// <summary> 
     /// IsShowSomething configuration value 
     /// </summary> 
     public static readonly bool IsShowSomething; 

    } 
} 

Save sau mã để * .tt tập tin và bao gồm tới yo dự án ur nơi bạn muốn đặt tập tin được tạo ra. Để tái tạo lớp trên mỗi xây dựng see my answer here Template nhận chuỗi, datetime, int và bool loại từ giá trị

<#@ assembly name="System.Core" #> 
<#@ assembly name="System.Xml" #> 
<#@ assembly name="System.Xml.Linq" #> 
<#@ import namespace="System" #> 
<#@ import namespace="System.Text" #> 
<#@ import namespace="System.IO" #> 
<#@ import namespace="System.Linq" #> 
<#@ import namespace="System.Xml.Linq" #> 
<#@ import namespace="Microsoft.VisualBasic" #> 
<#@ template language="VB" debug="True" hostspecific="True" #> 
<#@ output extension=".Generated.cs" #> 
<# 
    Dim projectNamespace as String = "MyProject.Core" 
    Dim className as String = "SiteSettings" 
    Dim fileName as String = "..\..\MyProject.Web\web.config" 

    Init(fileName) 

#> 
//------------------------------------------------------------------------------ 
// FileName = <#= path #> 
// Generated at <#= Now.ToLocaltime() #> 
// 
// <auto-generated> 
//  This code was generated by a tool. 
// 
//  Changes to this file may cause incorrect behavior and will be lost if 
//  the code is regenerated. 
//  
// NOTE: Please use the Add a Reference to System.Configuration assembly if 
//   you get compile errors with ConfigurationManager 
// </auto-generated> 
//------------------------------------------------------------------------------ 

using System; 
using System.Configuration; 

namespace <#= projectNamespace #> 
{ 
    /// <remarks> 
    /// You can create partial class with the same name in another file to add custom properties 
    /// </remarks> 
    public static partial class <#= className #> 
    { 
     /// <summary> 
     /// Static constructor to initialize properties 
     /// </summary> 
     static <#= className #>() 
     { 
      var settings = System.Configuration.ConfigurationManager.AppSettings; 
<#= AddToCostructor(path) #>  } 

<#= RenderApplicationSettings(path) #> } 
} 

<#+ 
    Dim path as String = "" 
    Dim doc as XDocument = Nothing 

    Public Sub Init(fileName as String) 
     Try 
      path = Host.ResolvePath(fileName) 
      If File.Exists(path) Then 
       doc = XDocument.Load(path) 
      End If 
     Catch 
      path = "<< App.config or Web.config not found within the project >>" 
     End Try  
    End Sub 

    Public Function AddToCostructor(ByVal path as String) as String     
     If doc Is Nothing Then Return "" 

     Dim sb as New StringBuilder() 

     For Each result as XElement in doc...<appSettings>.<add>    
      sb.Append(vbTab).Append(vbTab).Append(vbTab) 
      sb.AppendFormat("{0} = {1}(settings[""{0}""]);", [email protected], GetConverter([email protected])) 
      sb.AppendLine() 
     Next 

     Return sb.ToString() 

    End Function 

    Public Function RenderApplicationSettings(ByVal path as String) as String 
     If doc Is Nothing Then Return "" 

     Dim sb as New StringBuilder()  

     For Each result as XElement in doc...<appSettings>.<add>  
      dim key = [email protected] 
      sb.Append(vbTab).Append(vbTab) 
      sb.Append("/// <summary>").AppendLine() 
      sb.Append(vbTab).Append(vbTab) 
      sb.AppendFormat("/// {0} configuration value", key).AppendLine()    
      sb.Append(vbTab).Append(vbTab) 
      sb.Append("/// </summary>").AppendLine() 
      sb.Append(vbTab).Append(vbTab) 
      sb.AppendFormat("public static readonly {0} {1}; ", GetPropertyType([email protected]), key)  
      sb.AppendLine().AppendLine() 
     Next 

     Return sb.ToString() 

    End Function 

    Public Shared Function GetConverter(ByVal prop as String) as String  
     If IsNumeric(prop) Then Return "Convert.ToInt32" 
     If IsDate(prop) Then Return "Convert.ToDateTime" 
     dim b as Boolean 
     If Boolean.TryParse(prop, b) Then Return "Convert.ToBoolean"   
     Return "" 
    End Function 

    Public Shared Function GetPropertyType(ByVal prop as String) as String 
     If IsNumeric(prop) Then Return "int" 
     If IsDate(prop) Then Return "DateTime" 
     dim b as Boolean 
     If Boolean.TryParse(prop, b) Then Return "bool" 
     Return "string" 
    End Function 

#> 
+0

Đây là một ý tưởng thú vị, nhưng tôi không phải là một fan hâm mộ lớn của CodeSmith phải trung thực. Cuối cùng, tôi đã viết một lớp của riêng mình mà được yêu cầu trong mọi trường hợp vì không có cách nào để ứng dụng của tôi suy ra loại ứng dụng của tôi là gì. –

+1

Tôi đã thêm một chút mã vào bài đăng của mình. Hy vọng nó có thể giúp bạn. – Cheburek

+0

Đó là một giải pháp thực sự thú vị! Một điều có vẻ như có vấn đề với (và đây là VB IsNumeric) là "0,5,0" mà VB tin là một giá trị số, mặc dù tôi không chắc chắn như thế nào! –

1

Bạn có thể thực hiện việc này bằng bước dựng sẵn. Đây là cách dễ dàng để thực hiện - chỉ cần viết một chương trình hoặc tập lệnh hoặc mẫu để tạo lại lớp và gọi nó trong sự kiện dựng sẵn của bạn - nhưng điều này sẽ cung cấp cho bạn wigglies đỏ và không có bất kỳ thành viên mới nào cho đến khi lớp học được tái sinh.

Phương pháp tiếp cận thủ công hơn một chút, nhưng có lẽ thuận tiện hơn là tạo T4 template và bao gồm điều đó trong dự án của bạn. Tuy nhiên, bạn cần phải nhớ chuyển đổi lại mẫu mỗi lần bạn thêm cài đặt mới. Điều này có quá nguy hiểm không?

+0

Cảm ơn bạn đã trả lời của bạn! Thực tế tôi muốn rằng bất cứ điều gì tôi làm, toàn bộ quá trình populating lớp mặt tiền là tự động và không có công việc là yêu cầu của nhà phát triển. Có bất kỳ tài nguyên nào tồn tại từ trước mà bạn biết có thể làm điều này không? –

+0

Hmm, vì bạn đang ở trong ASP.NET, bạn có thể làm điều này bằng cách sử dụng không gian tên System.Web.Compilation, mà tôi nghĩ là những gì các dự án ASP.NET Web Site sử dụng để tạo các lớp hồ sơ của họ. Thật không may, đây là cách bên ngoài lĩnh vực kiến ​​thức của tôi, và tôi thậm chí không chắc chắn nếu nó hoạt động trong các dự án ứng dụng Web (.csproj-based). Lấy làm tiếc. Tùy chọn khác của bạn là xem xét các công cụ tùy chỉnh VS (IVsSingleFileGenerator) nhưng chúng được thiết kế cho một kịch bản khác và sẽ chỉ hoạt động nếu các định nghĩa cài đặt của bạn được lưu trong tệp đặc biệt của riêng chúng. – itowlson

+0

Điều này - http://blog.jqweb.ca/?p=44 - trông giống như một cái gì đó tôi có thể sử dụng, nhưng tôi sẽ cần phải thích ứng nếu để kéo từ db, chứ không phải là web.config ... Tôi ' sẽ cập nhật nếu/khi tôi tìm thấy một giải pháp. –

Các vấn đề liên quan