博客 (6)

public static class EntityFrameworkCoreExtension
{
    private static DbCommand CreateCommand(DatabaseFacade facade, string sql, out DbConnection connection, params object[] parameters)
    {
        var conn = facade.GetDbConnection();
        connection = conn;
        conn.Open();
        var cmd = conn.CreateCommand();
        cmd.CommandText = sql;
        cmd.Parameters.AddRange(parameters);
        return cmd;
    }

    public static DataTable SqlQuery(this DatabaseFacade facade, string sql, params object[] parameters)
    {
        var command = CreateCommand(facade, sql, out DbConnection conn, parameters);
        var reader = command.ExecuteReader();
        var dt = new DataTable();
        dt.Load(reader);
        reader.Close();
        conn.Close();
        return dt;
    }

    public static List<T> SqlQuery<T>(this DatabaseFacade facade, string sql, params object[] parameters) where T : class, new()
    {
        var dt = SqlQuery(facade, sql, parameters);
        return dt.ToList<T>();
    }

    public static List<T> ToList<T>(this DataTable dt) where T : class, new()
    {
        var propertyInfos = typeof(T).GetProperties();
        var list = new List<T>();
        foreach (DataRow row in dt.Rows)
        {
            var t = new T();
            foreach (PropertyInfo p in propertyInfos)
            {
                if (dt.Columns.IndexOf(p.Name) != -1 && row[p.Name] != DBNull.Value)
                {
                    p.SetValue(t, row[p.Name], null);
                }
            }
            list.Add(t);
        }
        return list;
    }
}

调用示例:

var data = db.Database.SqlQuery<List<string>>("SELECT 'title' FROM `table` WHERE `id` = {0};", id);


转自 我的个去 2 年前
1,871

测试在长度为 403 的字符串中查找,特意匹配最后几个字符:

string a = "";
for (int i = 0; i < 100; i++) { a += "aBcD"; }
a += "xYz";
string b = "xyz"; // 特意匹配最后几个字符

Stopwatch sw1 = Stopwatch.StartNew();
bool? r1 = null; 
for (int i = 0; i < 10000; i++) { r1 = a.IndexOf(b) >= 0; }
sw1.Stop();

Stopwatch sw2 = Stopwatch.StartNew();
bool? r2 = null; 
for (int i = 0; i < 10000; i++) { r2 = a.Contains(b); }
sw2.Stop();

Stopwatch sw3 = Stopwatch.StartNew();
bool? r3 = null; 
for (int i = 0; i < 10000; i++) { r3 = a.ToUpper().Contains(b.ToUpper()); }
sw3.Stop();

Stopwatch sw4 = Stopwatch.StartNew();
bool? r4 = null; 
for (int i = 0; i < 10000; i++) { r4 = a.ToLower().Contains(b.ToLower()); }
sw4.Stop();

Stopwatch sw5 = Stopwatch.StartNew();
bool? r5 = null; 
for (int i = 0; i < 10000; i++) { r5 = a.Contains(b, StringComparison.OrdinalIgnoreCase); }
sw5.Stop();

Stopwatch sw6 = Stopwatch.StartNew();
bool? r6 = null; 
for (int i = 0; i < 10000; i++) { r6 = a.Contains(b, StringComparison.CurrentCultureIgnoreCase); }
sw6.Stop();

Stopwatch sw7 = Stopwatch.StartNew();
bool? r7 = null; 
for (int i = 0; i < 10000; i++) { r7 = Regex.IsMatch(a, b); }
sw7.Stop();

Stopwatch sw8 = Stopwatch.StartNew();
bool? r8 = null; 
for (int i = 0; i < 10000; i++) { r8 = Regex.IsMatch(a, b, RegexOptions.IgnoreCase); }
sw8.Stop();

return Json(new
{
    IndexOf_________________ = sw1.Elapsed + " " + r1,
    Contains________________ = sw2.Elapsed + " " + r2,
    ToUpper_________________ = sw3.Elapsed + " " + r3,
    ToLower_________________ = sw4.Elapsed + " " + r4,
    OrdinalIgnoreCase_______ = sw5.Elapsed + " " + r5,
    CurrentCultureIgnoreCase = sw6.Elapsed + " " + r6,
    IsMatch_________________ = sw7.Elapsed + " " + r7,
    IsMatchIgnoreCase_______ = sw8.Elapsed + " " + r8,
});

结果参考:

{
"indexOf_________________": "00:00:00.1455812 False",
"contains________________": "00:00:00.0003791 False",
"toUpper_________________": "00:00:00.0038182 True",
"toLower_________________": "00:00:00.0026113 True",
"ordinalIgnoreCase_______": "00:00:00.0096550 True",
"currentCultureIgnoreCase": "00:00:00.1596517 True",
"isMatch_________________": "00:00:00.0053627 False",
"isMatchIgnoreCase_______": "00:00:00.0084132 True"
}


xoyozo 2 年前
1,315

百度地图天地图
初始化地图var map = new BMap.Map("allmap");var map = new T.Map("allmap");
将覆盖物添加到地图addOverlay(overlay: Overlay)addOverLay(overlay:OverLay)
从 Map 的 click 事件中获取坐标点

map.addEventListener("click", function (e) {

    Point = e.point;

}

map.addEventListener("click", function (e) {

    LngLat = e.lnglat;

}

坐标点new BMap.Point(lng: Number, lat: Number)new T.LngLat(lng: Numbe, lat: Number)
像素点new BMap.Pixel(x: Number, y: Number)new T.Point(x: Number, y: Number)
文本标注
new BMap.Label(content: String, {
    offset: Size,
    position: Point
})
new T.Label({
    text: string, 
    position: LngLat, 
    offset: Point
})
设置文本标注样式
setStyle(styles: Object)每个样式使用单独的 set 方法实现
图像标注
new BMap.Marker(Point, {
    offset: Size,
    icon: Icon,
    enableMassClear: Boolean,
    enableDragging: Boolean,
    enableClicking: Boolean,
    raiseOnDrag: Boolean,
    draggingCursor: String,
    rotation: Number,
    shadow: Icon,
    title: String
})
new T.Marker(LngLat, {
    icon: Icon,
    draggable: boolean,
    title: string,
    zIndexOffset: number,
    opacity: number
})
为图像标注添加文本标注Marker.setLabel(label: Label)

无。

可借用 title(鼠标掠过显示)属性来实现,并通过 Marker.options.title 来获取值

从图像标注获取坐标点Point = Marker.getPosition();
LngLat = Marker.getLngLat();
绘制折线
new BMap.Polyline(points: Array<Point>, {
    strokeColor: String,
    strokeWeight: Number,
    strokeOpacity: Number,
    strokeStyle: String,
    enableMassClear: Boolean,
    enableEditing: Boolean,
    enableClicking: Boolean,
    icons: Array<IconSequence>
})
new T.Polyline(points:Array<LngLat>, {
    color: string,
    weight: number,
    opacity: number,
    lineStyle: string
})
绘制多边形
new BMap.Polygon(points: Array<Point>, {
    strokeColor: String,
    fillColor: String,
    strokeWeight: Number,
    strokeOpacity: Number,
    fillOpacity: Number,
    strokeStyle: String,
    enableMassClear: Boolean,
    enableEditing: Boolean,
    enableClicking: Boolean
})
new T.Polygon(points:Array<LngLat>,{
    color: string,
    weight: number,
    opacity: number,
    fillColor: String,
    fillOpacity: number,
    lineStyle: string
})
设置多边形的点数组Polygon.setPath(points: Array<Point>)Polyline.setLngLats(lnglats: Array<LngLat>)
设置地图视野Map.setViewport(view: Array<Point> | Viewport, viewportOptions: ViewportOptions)Map.setViewport(view: Array<LngLat>)
xoyozo 5 年前
4,900

函数功能:添加/修改/删除/获取 URL 中的参数(锚点敏感)

/// <summary>
/// 设置 URL 参数(设 value 为 undefined 或 null 删除该参数)
/// <param name="url">URL</param>
/// <param name="key">参数名</param>
/// <param name="value">参数值</param>
/// </summary>
function fn_set_url_param(url, key, value) {
    // 第一步:分离锚点
    var anchor = "";
    var anchor_index = url.indexOf("#");

    if (anchor_index >= 0) {
        anchor = url.substr(anchor_index);
        url = url.substr(0, anchor_index);
    }

    // 第二步:删除参数
    key = encodeURIComponent(key);
    var patt;

    // &key=value
    patt = new RegExp("\\&" + key + "=[^&]*", "gi");
    url = url.replace(patt, "");

    // ?key=value&okey=value  -> ?okey=value
    patt = new RegExp("\\?" + key + "=[^&]*\\&", "gi");
    url = url.replace(patt, "?");

    // ?key=value
    patt = new RegExp("\\?" + key + "=[^&]*$", "gi");
    url = url.replace(patt, "");

    // 第三步:追加参数
    if (value != undefined && value != null) {
        value = encodeURIComponent(value);
        url += (url.indexOf("?") >= 0 ? "&" : "?") + key + "=" + value;
    }

    // 第四步:连接锚点
    url += anchor;

    return url;
}

/// <summary>
/// 获取 URL 参数(无此参数返回 null,多次匹配使用“,”连接)
/// <param name="url">URL</param>
/// <param name="key">参数名</param>
/// </summary>
function fn_get_url_param(url, key) {
    key = encodeURIComponent(key);
    var patt = new RegExp("[?&]" + key + "=([^&#]*)", "gi");

    var values = [];

    while ((result = patt.exec(url)) != null) {
        values.push(decodeURIComponent(result[1]));
    }

    if (values.length > 0) {
        return values.join(",");
    } else {
        return null;
    }
}


调用示例:

var url = window.location.href;

// 设置参数
url = fn_set_url_param(url, 'a', 123);

// 获取参数
console.log(fn_get_url_param, url, 'a');


压缩版:

function fn_set_url_param(b,c,e){var a="";var f=b.indexOf("#");if(f>=0){a=b.substr(f);b=b.substr(0,f)}c=encodeURIComponent(c);var d;d=new RegExp("\\&"+c+"=[^&]*","gi");b=b.replace(d,"");d=new RegExp("\\?"+c+"=[^&]*\\&","gi");b=b.replace(d,"?");d=new RegExp("\\?"+c+"=[^&]*$","gi");b=b.replace(d,"");if(e!=undefined&&e!=null){e=encodeURIComponent(e);b+=(b.indexOf("?")>=0?"&":"?")+c+"="+e}b+=a;return b}
function fn_get_url_param(b,c){c=encodeURIComponent(c);var d=new RegExp("[?&]"+c+"=([^&#]*)","gi");var a=[];while((result=d.exec(b))!=null){a.push(decodeURIComponent(result[1]))}if(a.length>0){return a.join(",")}else{return null}};


xoyozo 6 年前
3,196

在 ASP.NET Core 或 ASP.NET 5 中部署百度编辑器请跳转此文


本文记录百度编辑器 ASP.NET 版的部署过程,对其它语言版本也有一定的参考价值。

【2020.02.21 重新整理】


下载

从 GitHub 下载最新发布版本:https://github.com/fex-team/ueditor/releases

按编码分有 gbk 和 utf8 两种版本,按服务端编程语言分有 asp、jsp、net、php 四种版本,按需下载。


目录介绍

以 v1.4.3.3 utf8-net 为例,

ueditor 目录结构.png


客户端部署

本例将上述所有目录和文件拷贝到网站目录 /libs/ueditor/ 下。

当然也可以引用 CDN 静态资源,但会遇到诸多跨域问题,不建议。

在内容编辑页面引入:

<script src="/libs/ueditor/ueditor.config.js"></script>
<script src="/libs/ueditor/ueditor.all.min.js"></script>

在内容显示页面引入:

<script src="/libs/ueditor/ueditor.parse.min.js"></script>

如需修改编辑器资源文件根路径,参 ueditor.config.js 文件内顶部文件。(一般不需要单独设置)

如果使用 CDN,那么在初始化 UE 实例的时候应配置 serverUrl 值(即 controller.ashx 所在路径)。


客户端配置

初始化 UE 实例:

var ue = UE.getEditor('tb_content', {
    // serverUrl: '/libs/ueditor/net/controller.ashx', // 指定服务端接收文件路径
    initialFrameWidth: '100%'
});

其它参数见官方文档,或 ueditor.config.js 文件。


服务端部署

net 目录是 ASP.NET 版的服务端程序,用来实现接收上传的文件等功能。

本例中在网站中的位置是 /libs/ueditor/net/。如果改动了位置,那么在初始化 UE 的时候也应该配置 serverUrl 值。

这是一个完整的 VS 项目,可以单独部署为一个网站。其中:

net/config.json  服务端配置文件
net/controller.ashx  文件上传入口
net/App_Code/CrawlerHandler.cs  远程抓图动作
net/App_Code/ListFileManager.cs  文件管理动作
net/App_Code/UploadHandler.cs  上传动作

该目录不需要转换为应用程序。


服务端配置

根据 config.json 中 *PathFormat 的默认配置,一般地,上传的图片会保存在 controller.ashx 文件所在目录(即本例中的 /libs/ueditor/)的 upload 目录中:
/libs/ueditor/upload/image/
原因是 UploadHandler.cs 中 Server.MapPath 的参数是由 *PathFormat 决定的。

修改 config.json 中的 imagePathFormat 为例:

原值:"imagePathFormat": "upload/image/{yyyy}{mm}{dd}/{time}{rand:6}"

改为:"imagePathFormat": "/upload/ueditor/{yyyy}{mm}{dd}/{time}{rand:6}"

以“/”开始的路径在 Server.MapPath 时会定位到网站根目录。

此处不能以“~/”开始,因为最终在客户端显示的图片路径是 imageUrlPrefiximagePathFormat,若其中包含符号“~”就无法正确显示。

在该配置文件中查找所有 PathFormat,按相同的规则修改。


说到客户端的图片路径,我们只要将

原值:"imageUrlPrefix": "/ueditor/net/"

改为:"imageUrlPrefix": ""

即可返回客户端正确的 URL。

当然也要同步修改 scrawlUrlPrefix、snapscreenUrlPrefix、catcherUrlPrefix、videoUrlPrefix、fileUrlPrefix。


特殊情况,在复制包含图片的网页内容的操作中,若图片地址带“?”等符号,会出现无法保存到磁盘的情况,需要修改以下代码:

打开  CrawlerHandler.cs 文件,找到

ServerUrl = PathFormatter.Format(Path.GetFileName(this.SourceUrl), Config.GetString("catcherPathFormat"));

替换成:

ServerUrl = PathFormatter.Format(Path.GetFileName(SourceUrl.Contains("?") ? SourceUrl.Substring(0, SourceUrl.IndexOf("?")) : SourceUrl), Config.GetString("catcherPathFormat"));


如果你将图片保存到第三方图库,那么 imageUrlPrefix 值设为相应的域名即可,如:

改为:"imageUrlPrefix": "//cdn.***.com"

然后在 UploadHandler.cs 文件(用于文件上传)中找到

File.WriteAllBytes(localPath, uploadFileBytes);

在其下方插入上传到第三方图库的代码,以阿里云 OSS 为例:

// 上传到 OSS
client.PutObject(bucketName, savePath.Substring(1), localPath);

在 CrawlerHandler.cs 文件(无程抓图上传)中找到

File.WriteAllBytes(savePath, bytes);

在其下方插入上传到第三方图库的代码,以阿里云 OSS 为例:

// 上传到 OSS
client.PutObject(bucketName, ServerUrl.Substring(1), savePath);


最后有还有两个以 UrlPrefix 结尾的参数名 imageManagerUrlPrefix 和 fileManagerUrlPrefix 分别是用来列出上传目录中的图片和文件的,

对应的操作是在编辑器上的“多图上传”功能的“在线管理”,和“附件”功能的“在线附件”。

最终列出的图片路径是由 imageManagerUrlPrefiximageManagerListPath + 图片 URL 组成的,那么:

"imageManagerListPath": "/upload/ueditor/image",

"imageManagerUrlPrefix": "",

以及:

"fileManagerListPath": "/upload/ueditor/file",

"fileManagerUrlPrefix": "",

即可。

如果是上传到第三方图库的,且图库上的文件与本地副本是一致的,那么将 imageManagerUrlPrefix 和 fileManagerUrlPrefix 设置为图库域名,

服务端仍然以 imageManagerListPath 指定的路径来查找本地文件(非图库),但客户端显示图库的文件 URL。

因此,如果文件仅存放在图库上,本地没有副本的情况就无法使用该功能了。

综上,所有的 *UrlPrefix 应该设为一致。


另外记得配置不希望被远程抓图的域名,参数 catcherLocalDomain


服务端授权

现在来判断一下只有登录用户才允许上传。

首先打开服务端的统一入口文件 controller.ashx

继承类“IHttpHandler”改为“IHttpHandler, System.Web.SessionState.IRequiresSessionState”,即同时继承两个类,以便可使用 Session,
找到“switch”,其上插入:

if (用户未登录) { throw new System.Exception("请登录后再试"); }

即用户已登录或 action 为获取 config 才进入 switch。然后,

else
{
    action = new NotAllowedHandler(context);
}

这里的 NotAllowedHandler 是参照 NotSupportedHandler 创建的,提示语 state 可以是“登录后才能进行此操作。


上传目录权限设置

上传目录(即本例中的 /upload/ueditor/ 目录)应设置允许写入和禁止执行。


基本用法

设置内容:

ue.setContent("Hello world.");

获取内容:

var a = ue.getContent();

更多用法见官方文档:http://fex.baidu.com/ueditor/#api-common


其它事宜

配置上传附件的文件格式

找到文件:config.json,更改“上传文件配置”的 fileAllowFiles 项,

同时在 Web 服务器上允许这些格式的文件可访问权限。以 IIS 为例,在“MIME 类型”模块中添加扩展名。


遇到从客户端(......)中检测到有潜在危险的 Request.Form 值。参考此文


另外,对于不支持上传 .webp 类型的图片的问题,可以作以下修改:
config.json 中搜索“".bmp"”,替换为“".bmp", ".webp"
IIS 中选中对应网站或直接选中服务器名,打开“MIME 类型”,添加,文件扩展名为“.webp”,MIME 类型为“image/webp


最后,为了在内容展示页面看到跟编辑器中相同的效果,请参照官方文档引用 uParse

若有插入代码,再引用:
<link href="/lib/ueditor/utf8-net/third-party/SyntaxHighlighter/shCoreDefault.css" rel="stylesheet" />
<script src="/lib/ueditor/utf8-net/third-party/SyntaxHighlighter/shCore.js"></script>

其它插件雷同。


若对编辑器的尺寸有要求,在初始化时设置即可:

var ue = UE.getEditor('tb_content', {

  initialFrameWidth: '100%',
  initialFrameHeight: 320
});


图片等附件上传到阿里云 OSS 参考此文

xoyozo 8 年前
5,636


--------------------
常量:
整型,实型,布尔值,字符串型,null,undefined

变量:var
--------------------
除法运算:9/4 = 2.25 (而不是2)

--------------------
系统函数:
1,encodeURI URL编码
   var urlStr=encodeURI("http://www.abc.com/?country=吴&name=z x");
   结果:http://www.abc.com/?country=%E5%90%B4&name=z%20x
2,decodeURI URL解码
3,parseInt 将字符串按指定进制转换成一个整数,参数二表示进制
   parseInt("32",10) 结果:32
   parseInt("3c2",10) 结果:3
   parseInt("c32",10) 结果:NaN
   parseInt("0x18",10) 结果:0
   parseInt("12",16) 结果18
4,parseFloat 将字符串转成小数
   parseFloat("2.5") 结果:2.5
   parseFloat("2.c5") 结果:2
   parseFloat("c2.5") 结果:NaN
5,isNaN 用于检测parseInt和parseFloat返回是否为NaN
   返回true/false
6,escape 编码
   非ASCII替换为%xx
7,unescape 解码
8,eval 将字符串作为JS表达式执行,例
   for(var i=0;i<3;i++) eval("var a"+i+"="+i);
   相当于:
   var a0=0; var a1=1; var a2=2;
--------------------
对象
1,Object
2,String
   方法:
   indexOf,
   lastIndexOf,
   match,使用正则表达式模式对字符串执行搜索,返回包含该搜索结果的数组
   replace,
   search,使用正则表达式搜索,第一个匹配的字符的位置
   slice,截字符串:参数一,开始位置,参数二,结束位置(不指定或为-1时表示末位置)
   split,返回一个字符串按照某种分隔标志符拆分为若干子字符串时所产生的字符串数组,分隔符可以是多个字符或一个正则表达式,它不作为任何数组元素的一部分返回。
   substr,截字符串:参数一,开始位置,参数二,长度
   toLowerCase,
   toUpperCase,
3,Math(不能用new创建)
   方法:
   abs,绝对值
   sin,cos,正余弦
   asin,acos,反正余弦
   random,返回介于0~1之间的伪随机数
   例:var num = Math.randow();
4,Date
    var currentTime=new Date();
    //var currentTime=new Date(2002,3,4);
    var strDate=currentTime.getYear()+"年";
    strDate+=currentTime.getMonth()+"月";
    strDate+=currentTime.getDate()+"日";
    strDate+=currentTime.getHours()+":";
    strDate+=currentTime.getMinutes()+":";
    strDate+=currentTime.getSeconds()+" ";
    strDate+=currentTime.getMilliseconds();
    alert(strDate);
   结果:2008年1月19日15:27:10 518
----------------------
数组
1,
    var arr=["abc",123,'abc',,3.4];
    for(var i=0;i<arr.length;i++)
    {
        alert(arr[i]);
    }
2,用对象的方式实现数组
    function MyArray(){this.length=arguments.length;for(var i=0;....
3,Array对象
    var arr=new Array(2.4,"abc",2);
    arr.sort(); //排序
    alert的结果为 2 2,4 abc
-----------------------

xoyozo 16 年前
3,932