2020年6月9日 星期二

使用MVC Bundle後,CSS參考的相對路徑不對了??

MVC Bundle相當好用,可以把一堆css, js包在一起
bundles.Add(new StyleBundle("~/css/main").Include(
    "~/Content/Layout/main.css",
    "~/Content/bootstrap.css",
    "~/Content/font-awesome.css",
    "~/Content/flags.css"));

bundles.Add(new ScriptBundle("~/js/main").Include(
    "~/Scripts/jquery-{version}.js",
    "~/Scripts/bootstrap.bundle.js",
    "~/Scripts/Layout/main.js",
    "~/Scripts/TreeTable/javascript.js"));

只要在cshtml裡寫進以下語法, 就可以使用這一堆的css,js, 還有其它優點可以再上網查查
@Styles.Render("~/css/main")
@Scripts.Render("~/js/main")

但我最近在使用FlagSprites這個顯示國旗的小套件的時候

發現Release到Server上後沒辦法顯示出來

追了一下發現 flags.css 的內容包含了一個相對路徑
.flag {
	width: 16px;
	height: 11px;
	background:url(flags.png) no-repeat
}
但實際引用的位址卻是這個,當然找不到圖片


解決方法1


使用CssRewriteUrlTransform
bundles.Add(new StyleBundle("~/bundles/css").Include(
    "~/Content/bootstrap.css",
    "~/Content/font-awesome.css").Include(
    "~/Content/flags.css", new CssRewriteUrlTransform()));
它會將css裡的路徑都轉成根目錄的相對路徑






但這個方法如果程式不是掛在根目錄下,而是某個站台下的話,
路徑還是一樣會有問題

解決方法2


使用套件BundleTransformer.Core
先從nuget下載




修改BundleConfig.cs
using BundleTransformer.Core.Transformers;

var stylebundle = new StyleBundle("~/bundles/css").Include(
    "~/Content/bootstrap.css",
    "~/Content/font-awesome.css"
    "~/Content/flags.css"));
stylebundle.Transforms.Add(new StyleTransformer());
bundles.Add(stylebundle);
這套件會判斷程式掛載的位置來修改css的路徑

所以只要用上述步驟打包css檔,即可正常載入至網頁中,
也不用考慮網站掛在哪個站台底下,相當方便。

結束,收工!!

 參考 .Net 蛤什麼?

2020年5月18日 星期一

Quartz.NET 讓你的網站也可以開始自動排程

前言


目前工作的專案如果有排程的需求(ex. 每天寄信、產生報表之類的)

大部分都是寫一隻程式然後放進Windows排程去執行,

如果是要產生報表資料則會用Mysql的event去跑。

日前收到了一包.net core 的source code,發現裡頭用了 Pomelo.AspNetCore.TimedJob 這個

可以定期執行任務的類別庫,才知道原來有這類型工具可以用啊

所以也想在目前手上的mvc.net 專案裡,增加相同的功能。

servey了一下,發現蠻人多推薦Quartz.NET這個套件,

立馬下載來用,果然是好物!


安裝

直接從NuGet直接下載安裝吧









練習

主要需要實作3個相關的介面、類別

建立排程器:IScheduler、StdSchedulerFactory
建立工作:IJobDetail、IJob:
建立觸發器:ITrigger、TriggerBuilder


1. 首先建立工作的類別
[DisallowConcurrentExecutionAttribute]
public class Job_UpdateDeviceOnlineStatus : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        return Task.Run(()=> {
            //update device online status 
        });
    }
}
工作內容是去檢查遠端device是否連線,先不多述

加上[DisallowConcurrentExecutionAttribute]

可以避免類別instance兩次,代表同時間只執行一次工作


2. 修改Global.asax,讓程式啟動的時候去加入排程工作
IScheduler scheduler = null;

protected void Application_Start()
{
    ...前略
    StartSchedulerJon();
}

protected void Application_End(Object sender, EventArgs e)
{
    scheduler?.Shutdown();
}

private async void StartSchedulerJon()
{
    try
    {
        //建立排程器
        var factory = new Quartz.Impl.StdSchedulerFactory();
        scheduler = await factory.GetScheduler();

        //建立工作
        IJobDetail job = JobBuilder.Create<Job_UpdateDeviceOnlineStatus>()
            .WithIdentity("OnlineStatusUpdate")
            .Build();

        //建立觸發器
        ITrigger trigger = TriggerBuilder.Create()
            .WithSimpleSchedule(x => x
                .WithIntervalInMinutes(5)
                .RepeatForever())
            .WithIdentity("trigger_OnlineStatusUpdate")
            .StartNow()
            .Build();

        await scheduler.ScheduleJob(job, trigger);
        await scheduler.Start();

    }
    catch(Exception ex)
    {
        //log
        Console.Error.Write(ex.Message);
    }
}

trigger的時間有兩種表示方式,另一種是用CRON表示法

想將windows排程工作轉到.net應用程式裡,這種方式或許比較適合
ITrigger trigger2 = TriggerBuilder.Create()
    .WithCronSchedule("0 0/5 * * * * ") //每5分鐘跑一次
    .WithIdentity("trigger_use_cron")
    .StartNow()
    .Build();


3. 修改Web.config
一些排程的參數放在config檔裡(ex. 時間、enable),可以比較彈性的去調整配置
這次先不做~懶


4.IIS 8.0 設定
*IIS需安裝"應用程式初始化"
*修改應用程式集區的進階設定,將「啟動模式」從預設的「OnDemand」改為「AlwaysRunning」
*修改網站的進階設定,把「預先載入已啟用」(Preload Enabled)由預設的 False 改為 True。


後記

簡單的實作就可以有強力大功能,

也要繼續觀查長期執行下來對Server有沒有什麼其它影響

其它詳細的內容請參考官網文件說明



參考
Huanlin學習筆記
官網

2020年5月17日 星期日

Dynamic LinQ 讓LinQ更彈性好用的Extension

無意間發現的好工具來記錄一下。

當我們使用Linq做排序或where查詢時會用expression表示如下
var query = SampleList.Where(c=>c.online==true).OrderBy(c=>c.Name);

但當我們只能用欄位名稱的字串來操作時,則需要額外多寫一堆程式碼來實現
IEnumerable orderby(string condition, IEnumerable acc)
{
    if(condition=="online")
        return acc.OrderBy(c=>c.online);
    else if(condition == "name")
        return acc.OrderBy(c=>c.Name);
    .......
}
很冗長吧…
如果我table欄位有一堆不就寫不完了
Dynamic Linq直接幫我們解決這方面的問題,直接來看吧。

先從Nuget 下載吧


宣告一個class
public class Car
{
    public string Brand { set; get; }
    public string Color { set; get; }
    public int Count { set; get; }
}

sample code


Where 要用參數方式代入 (@0, @1...)
List cars = new List()
{
    new Car(){Brand="honda", Color="White", Count=5 },
    new Car(){Brand="toyota", Color="Red", Count=10 },
    new Car(){Brand="Benz", Color="Black", Count=3 }
};
            
Console.WriteLine("原始順序");
foreach(var c in cars)
    Console.WriteLine($"{c.Brand} {c.Color} {c.Count}");

Console.WriteLine("\r\n使用order count desc");
var query = cars.OrderBy("Count desc");//用descending也ok
foreach (var c in query)
    Console.WriteLine($"{c.Brand} {c.Color} {c.Count}");

Console.WriteLine("\r\n使用where color=white");
var query2 = cars.Where(" Color=@0", "White");
foreach (var c in query2)
    Console.WriteLine($"{c.Brand} {c.Color} {c.Count}");

result


很方便吧,整個大大簡省了coding的時間

但這方法無法在編譯時知道是否有錯誤發生,只能在runtime時期才知道程式有錯

所以要做好錯誤處理,就是記得要加上try...catch啦








參考
dotblog搞搞就懂

2019年7月10日 星期三

名稱'ViewBag' 不存在於目前的內容中


已經忘了是從什麼時候專案裡cshtml的@ViewBag下面都跑出了擾人紅色毛毛蟲,包含連@Url, @Style, @Script 等都有出現,雖然在執行、發佈上是完全沒有任何問題,但在coding的時候還是會造成麻煩,所以決定一定要把它給處理掉。
上網搜尋了幾個方法,找到了幾個方向

1.View/Web.config修正













如果從空白專案開始,有可能會少了View/Web.config這個檔案
但我原本的web.config就好好的,所以…無效!!

2.刪除快取

將C:\Users\your.name.here\AppData\Local\Microsoft\VisualStudio\14.0\ComponentModelCache 底下的文件刪除,再重啟vs

 把快取刪掉再重新產生,感覺蠻有機會 應該是快取錯亂才找不到ViewBag吧。
 但實驗結果…失敗,毛毛蟲依舊存在

3.Resetting user data

這動作會需要重新登入microsoft帳號
執行以下指令
devenv.exe /resetuserdata
 並刪除.vs 資料夾

結果…還是一樣!!(怒

4. webconfig 版號確認

我有另一個專案是用mvc5, 就沒這個問題,
所以我把這個專案從mvc4 更新到mvc5,但還是一樣有毛毛

在思考會不會是版本的引用上面有錯誤,

後來發現原來是webpage:version的值之前被我改到,拿去做其它用途,
但它原來是會驗證元件版本的key,改回原本版號就ok了






繞了一圈,結果還是回到web.config上
上了一課,不知道的key還是不要亂動~>"<


參考
stackoverflow
stevefenton

2019年7月5日 星期五

MVC如何新建 BundleConfig

在空白專案裡新增BundleConfig

1.安裝Nuget Package Microsoft.AspNet.Web.Optimization到專案裡
開啟 工具>NuGet套件管理員>套件管理器主控台
輸入 Install-Package Microsoft.AspNet.Web.Optimization

2.新增BundleConfig.cs檔
在APP_Start裡新增BundleConfig.cs,並加入以下內容
using System.Web;
using System.Web.Optimization;

namespace yourprojectname
{
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));
            bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include("~/Scripts/jquery-ui-{version}.js"));
            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include("~/Scripts/jquery.unobtrusive*", "~/Scripts/jquery.validate*"));
            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include("~/Scripts/modernizr-*"));
        }
    }
}

3.修改Global.asax,加入以下內容
using System.Web.Optimization;

void Application_Start(object sender, EventArgs e)
{
    ...
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

4.修改在專案web.config跟views資料夾下的web.config
加入命名空間
namespace="System.Web.Optimization"

5.在cshtml檔裡 render bundle,開始使用bundle打包的功能
@Scripts.Render("~/bundles/jquery"")
@Scripts.Render("~/bundles/jqueryval"")


參考
stackoverflow.com
aspnetmars.blogspot.com

使用MVC Bundle後,CSS參考的相對路徑不對了??

MVC Bundle相當好用,可以把一堆css, js包在一起 bundles.Add(new StyleBundle("~/css/main").Include( "~/Content/Layout/main.css", ...