文章出處

  • EF7 的糾纏
  • ASP.NET 5 的無助
  • 忘不了你的好

一開始列出的這個博文大綱,讓我想到了很久之前的一篇博文:戀愛雖易,相處不易:當EntityFramework愛上AutoMapper,只不過這次的劇情換主角了,而且與 EF 和 AutoMapper 愛情故事不同的是,這次是個悲劇。

對 ASP.NET 5 和 EF7 的感情,從她倆一出生,我就不可自拔的愛上她們了,不要嫌哥多情,有“情”,就是任性。

從一開始的一見鐘情,到慢慢的深入了解,再到最后的抉擇與無奈,不管結局如何如何,其實這個過程,已經讓我們彼此學到了很多,也成長了很多。

EF7 的糾纏

前段時間,重寫之前的一個項目,選擇的是用 ASP.NET 5+EF7 進行開發,因為我自己很喜歡 EF,所以一開始就先研究的 EF7,當看到 Code First Only,以及跨平臺的支持(和我關系不大)等等,非常的激動,記得當時還紀錄了一篇博文:EF7 Code First Only-所引發的一些“臆想”,有人會說,對于 EF 的開發模式,EF7 的功能又不是增加,而是減少了(Only),有必要這么大驚小怪嗎?當然表面上來說,確實沒有什么驚奇的地方,但自己深入一想,Only 關鍵字,所傳遞的一些信息卻是另一層面的東西,那篇博文中已經寫的很詳細了,這邊就不啰嗦了。

對于 EF7 的項目應用,我自己是充滿信心的,不管遇到什么問題,我也都想盡辦法去解決,無奈的是網上資料太少,谷歌搜索一些 EF7 問題關鍵詞,基本上找不到對應的解決方案,所以有些東西只能自己去摸索,去實踐,但這樣也會造成,往往一個很簡單的問題,自己卻想的很復雜,最后就不知不覺的陷在里面,而且越是解決不了,自己就越想解決,然后就陷入一個惡性循環,最后呢?這個問題還是沒有解決,這樣所造成的結果是什么呢?很簡單,寶貴的時間被浪費了,沒辦法,這也是新技術所應用的成本。

我記得有一個 EF7 Migration 的問題,這個問題大概花了我兩三天的時間,是的,兩三天的時間啊,一直在解決這個問題,最后呢?很顯然,沒有解決,而且之后的幾天一直在郁悶,壓抑的感覺越來越強烈,當一個問題存在你心中很久很久,你就越想解決它,這個想法也就會變的越來越強烈,所以你需要你個發泄點,什么呢?就是寫博文。轉移注意力,也算是一種吐槽,就紀錄了一篇博文:

這篇博文前面部分是一些 EF7 的簡單使用,比如鏈接與實體映射配置等,當然用過之后,你會發現和 EF 的其他版本差別很大,不可否認,非常強大,也更加“人性化”,比如最愛的:OneToOne、OneToMany 和 ManyToOne,簡單、直接、明了。博文的后半部分主要紀錄我遇到的 EF7 Migration 問題,當然只是一個紀錄,沒有說明其解決方式,當時紀錄的目的也更多的是一種吐槽,或者自我發泄,但沒想到有一位園友 JeffreyWu,回復中貼出的一個參考鏈接,打開了自己的一扇窗,真心非常感謝他,而且當時的心情真是描述不出來,就像烏云之后的晴天,壓抑自己的一個問題,終于被解決了,那種感覺真是比中 500W 彩票的感覺還要好。

其實你發現,EF7 Migration 的問題解決很簡單,就是換一種方法:使用 KVM 進行命令操作,而我那幾天時間卻一直撲在:怎么使用 Package Manager Console 進行 EF7 Migration 操作?而且一直陷在里面,最后卻解決不了。所以通過這件事,我自己也收獲了一點,那就是如何解決問題?如果一個問題在一個場景中自己始終解決不了,不妨跳出這個場景,換一種思路去解決,不經意的一瞬間,也許這個問題就可以解決了。當然收獲的最重要一點是:有問題,寫博文,拋出問題,之后零零散散紀錄了一些:

上面這些 EF7 問題,都是項目應用中所遇到的,而且是最最普通的問題。通過之前 EF7 Migration 的事件,我自己在解決上面問題中,對于每一個問題,給自己的解決時間為最多半天,如果自己在半天時間內解決不了,那就換一種思路,或者用另外一種方式去實現,達到同樣的效果即可,所以對于上面每一個問題,我都沒有像 EF7 Migration 一樣,陷在里面過,當然有的解決了,有的沒有解決,比較好的是,可以用另一種方式實現同樣的效果。

在博文中,有園友說可以把問題提交給:EntityFramework 7 Issues,然后我也順便提交了幾個,當時看到 issues 中那幾百個問題,而且大部分都是 Open 狀態,Closed 的很少,對于提交的問題,我的想法是希望自己的寫法有問題,而不是 EF7 本身的問題,因為我項目正在使用它,我自己的問題可以解決,如果是它的問題,要等它解決,這就需要時間,不知道何年何月,但事實卻是,提交的幾個問題都是 Bug:

這個很無奈,但通過這件事你會發現除這件事之外的很多東西,比如,因為開源,因為社區,你可以干很多事情,如果自己有能力,有時間,你完全可以去查看 EF7 的源代碼,去幫微軟解決問題,然后隨意的和大洋彼岸寫 C# 最好的程序員交流,當然能干這些的前提條件很多。

其實這些問題最后確診為“Bug”,就致使我對使用 EF7 產生了一些動搖,畢竟她現在還處在 Beta 階段,她還年輕,需要時間成長,而我卻沒有時間陪她、等她,這也許是我和她之間的一種無奈吧。

ASP.NET 5 的無助

ASP.NET 5 之前的名字叫 ASP.NET vNext,其實我對她就像是與鄰班的女同學,見過幾面,卻不怎么了解。對于 ASP.NET 5,說白了,我頂多是做了幾個 Demo,并沒有用于生產環境,從 ASP.NET 5 的目錄結構或者其他文章的運行機制介紹中,你就可以看出 ASP.NET 5 這次的改變是翻天覆地的,但簡單的 Demo 說明不了什么問題,其實在現有的 ASP.NET 5 項目中,我也寫了不少的代碼,但都局限于 Controller 和 View 的使用,對于這塊,你可以像使用之前 MVC 版本一樣,在這部分中,你能體會到它的改變很少,最多你會發現,在 Views 目錄下居然沒有了 Web.config,除了 Controller 和 View,在 ASP.NET 5 中,我寫代碼最多的地方就是 MapRoute 路由配置了,這個不得不說非常強大,寫起來也非常的爽,詳細內容后面再說。

關于 ASP.NET 5,我只紀錄一點,昨天進行 ASP.NET 5 項目的身份驗證開發,也就是類似之前 MVC 的 FormsAuthentication.SetAuthCookie 操作,你會發現在 ASP.NET 5 中,沒有了這段代碼,身份驗證操作采用類似于 Owin 形式的,但這個我沒接觸過,所以不是很了解,關于這個問題,我給自己一天的時間去解決,或者做出一個可以運行的 IdentityDemo,結果呢?我想你已經猜到了,沒有完成。

關于 ASP.NET 5 的學習,微軟提供了一個 ASP.NET 5 版本的 MusicStore 項目,對于學習資料很少的 ASP.NET 5 來說,這是相當寶貴的,關于身份驗證的實現,我當時也希望可以從這個項目中得到一些啟發,但遺憾的是沒有找到我所需要的,我稍微貼一下這部分的實現代碼。

AccountController:

[Authorize]
public class AccountController : Controller
{
    public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
    {
        UserManager = userManager;
        SignInManager = signInManager;
    }

    public UserManager<ApplicationUser> UserManager { get; private set; }
    public SignInManager<ApplicationUser> SignInManager { get; private set; }

    // GET: /Account/Login
    [HttpGet]
    [AllowAnonymous]
    public IActionResult Login(string returnUrl = null)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        if (ModelState.IsValid)
        {
            var signInStatus = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
            switch (signInStatus)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid username or password.");
                    return View(model);
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }
}

ConfigureServices:

// Add Identity services to the services container.
services.AddDefaultIdentity<ApplicationDbContext, ApplicationUser, IdentityRole>(Configuration);

這只是示例項目中的部分代碼,除了 ConfigureServices 中的這部分的配置,其實還有 services.AddIdentity<IdentityUser>();app.UseIdentity(); 等等,到現在我都不明白這其中的區別,或者所不同的作用,在之前的 MVC 版本中,我們一般在 Web.config 中進行下面配置:

<system.web>
  <authentication mode="Forms">
    <forms name=".DottextCookie" loginUrl="~/Account/Login" protection="All" domain=".demo.com" protection="All" timeout="43200" path="/" />
  </authentication>
  <compilation debug="true" targetFramework="4.5.3" />
  <httpRuntime />
</system.web>

而在 ASP.NET 5 中沒有了 Web.config,哪該怎么進行配置?MusicStore 中并沒有這部分的實現,找資料后發現,要這樣進行配置:

app.UseCookieAuthentication((cookieOptions) =>
{
    cookieOptions.AuthenticationType = ClaimsIdentityOptions.DefaultSecurityStampClaimType;
    cookieOptions.AuthenticationMode = AuthenticationMode.Active;
    cookieOptions.CookieHttpOnly = true;
    cookieOptions.CookieName = ".DottextCookie";
    cookieOptions.LoginPath = new PathString("/Account/Login");
    cookieOptions.CookieDomain = ".demo.com";
}, "AccountAuthorize");

project.json 配置:

"dependencies": {
    "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta1",
    "Microsoft.AspNet.Identity": "3.0.0-beta1",
    "Microsoft.AspNet.Security": "1.0.0-beta1",
    "Microsoft.AspNet.Security.Cookies": "1.0.0-beta1"
}

Security 類似于關聯賬戶登錄,比如你可以在 ASP.NET 5 中,增加外部賬戶驗證(Google、Facebook 賬戶等等),那 Microsoft.AspNet.Identity.EntityFramework 是什么?身份驗證怎么和 EF 扯到一起了,這個是 ASP.NET 5 中新增的一個功能,你可以進行配置身份驗證的 DbContext,就比如上面 ConfigureServices 中的配置代碼,然后綁定之后,你可以很方便的進行身份驗證操作,比如 Login、Register、Manage 和 LogOff 等等,找到一篇示例說明:

越扯越多了,這部分內容,可以另外寫篇博文說明,其實最后我想要的功能是不綁定 DbContext,在 ASP.NET 5 項目中,只進行判斷操作,身份驗證在另外服務中進行,然后在本項目中可以實現類似 FormsAuthentication.SetAuthCookie 操作就可以了,但最后做了幾個 Demo 都不能實現,規定的一天時間,已經用完了,所以。。。

還有一個問題是如何在 ASP.NET 5 項目中添加 Web 引用,比如 WCF,但你發現在 Web 項目或是類庫項目,并沒有“Add Web Reference”這個選項,比如這個帖子:Add Web Service Reference in VS 2015,沒人回答,搜索之類的關鍵詞,如果有回答,大部分是:no,那如果不支持的話,可以換一種思路去解決,比如使用 WebAPI,當然現在也比較流行這個,但這就會造成一個重寫成本,你需要額外進行考慮。

VS2015 提供了 ASP.NET 5 項目的兩個模版,你如果仔細看,在其模版圖標上面有個“vNext”的字樣,這是和其他模版所不一樣的地方,之前有提到過,ASP.NET 5 Web 和 ASP.NET 5 Class Library 只能相互引用,其他版本的項目或類庫不能引用或被引用,這種“隔離”讓我多了一份“憂慮”。

除了上面的幾個問題,其實 ASP.NET 5 在應用中還有很多未知的問題,只不過現在還沒遇到罷了,不是說這些問題不能解決,而是說解決這些問題需要時間,當然,如果你有充足的時間,那可以隨意的去”折騰“,但公司畢竟不是科學院,做產品也不是搞科研,沒有那么多的時間去研究。所以,對于我來說,比如身份驗證的實現,我只給自己一天的時間,如果解決不了,那就考慮其他方式,但對于之后的開發,我覺得再這樣下去,項目幾個月也開發不完,畢竟未知的東西需要時間進行探索,而這就是技術時間成本,所以開發模式需要調整,所以。。。

重要更新:跌倒了,再爬起來:ASP.NET 5 Identity

忘不了你的好

在寂寞的長巷,我們見了最后一面,你說散就散,我也不想再和你爭辯,誰能阻擋新的重逢,忘不了你的錯,忘不了你的好,忘不了雨中的散步,也忘不了那風里的擁抱。。。-陶喆《忘不了》

昨天思考了一晚上,終于做出了抉擇:拋棄 ASP.NET 5 和 EF7,然后今天早上花了大概半天的時間,去遷移現在用 ASP.NET 5 和 EF7 實現的代碼,然后換做 ASP.NET MVC 5 和 EF6 去實現,其實決定和遷移的過程中,內心是沉重的,因為自己沒有堅持下來,包括今天晚上寫這篇博文,我的心情也是復雜的,但沒辦法,我覺得這個無奈的決定,對我來說,是最好的選擇,咳咳,說的有點像分手的感覺,打住!

在遷移代碼的過程中,和 ASP.NET MVC 5 和 EF6 實現對比后,發現原來 ASP.NET 5 和 EF7 也是如此的美好,下面紀錄一下自己記得的幾點:

  1. project.json 程序包管理的好處:在 ASP.NET 5 類型的項目中,添加程序包的引用非常簡單,只需要在 project.json 的 dependencies 中,寫對應的程序包名稱就行了,如果刪除操作,直接 Control+X 就可以了,而在非 ASP.NET 5 項目中,你需要 packages.config 進行配置管理,更重要的一點,比如針對 EF 的單元測試項目,那你需要在此項目中添加 EF 的引用,然后還需要在 app.config 中,進行鏈接配置,而在 ASP.NET 5 項目中,只需要添加需要單元測試的項目即可,因為它會自動加載所依賴項。
  2. EF7 Linq 的強大:這個我也不知道是不是 EF Linq 的問題,就是在編寫 Linq 代碼的時候,一般會有一個 Select 操作,我們一般會在里面動態拼接 DTO 對象,但有時候我們也會加一些判斷,或者字符串轉化操作,比如 DateFormat = DateAdd.ToString("yyyy-MM-dd HH:mm"),這個操作在 EF7 中是可以的,但在 EF6 中卻報一個類似“表達式不支持 ToString”的異常。
  3. EF7 與 AutoMapper 結合的強大:這個主要是對 .Project().To<SimpleDTO>() 的操作,如果這樣使用,會不支持映射的 ResolveUsing 配置,記得還紀錄過一篇博文:AutoMapper Project To not support ResolveUsing,雖然不支持 ResolveUsing,但在博文中,提到了一種替換方法,比如 ForMember(dto => dto.Name, opt => opt.MapFrom(ol => NameCustomResolver(ol))),就是自行寫 Resolver 轉換方法,但這個配置卻在 EF6 中報錯,而在 EF7 中卻是可以的。
  4. MapRoute 的強大:這個深有體會,因為原來在 ASP.NET 5 中寫的路由配置代碼,居然在 ASP.NET MVC 5 中報錯了,比如下面一段路由配置:

    routes.MapRoute(
    name: "demo_type",
    template: "n/{typeName}/{page?}",
    defaults: new { controller = "Home", action = "Index" });
    這段代碼會在 ASP.NET MVC 5 中,報無法識別"?"的異常,如果對于參數操作,我們一般會進行這樣配置: page = UrlParameter.Optional,還有一點是,在 ASP.NET MVC 5 中,無法識別 {action}(這個花了很多時間去兼容解決,有時間再紀錄下),而在 ASP.NET 5 中,卻是可以的。
  5. 幸好的支持:我在 ASP.NET 5 中,使用了一些 C# 6.0 的特性,使用最多的是引用靜態類和字符串變量拼接,遷移之前,我還擔心會不支持,要不然的話,就需要改一大堆的代碼。還好沒什么問題。
  6. 不記得了。

對于 EF7 來說,自己花了太多時間和她“糾纏”,對于 ASP.NET 5 來說,自己對她是一種“無助”,這些都需要時間去完善,畢竟她們還是那么的年輕,也希望園友們可以多多“折騰”她們,然后把一些實用的心得分享出來,有時候你會發現,當搜索一個問題,如果找到的話,那是驚喜的感覺,如果沒有找到的話,那是一種絕望的感覺,社區需要分享。

對于我自己來說,這次失敗的“抉擇”,總結一下原因:

  1. 能力有限;
  2. 時間有限;
  3. 資料有限。

文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()