當前位置:
首頁 > 知識 > C# ftp 圖片上傳多快好省

C# ftp 圖片上傳多快好省

前言

此篇講到的是圖片上傳功能,每個網站必定會有這樣類似的功能,上傳文件、上傳圖片等等。那麼接下來,看看我們EF+uploadfile+ftp如何玩轉上傳圖片吧

效果預覽

C# ftp 圖片上傳多快好省

具體實現

一個簡單資料庫 只有一個主鍵Id,一個身份證正面路徑和一個身份證背面路徑三個欄位。

首先呢,我們把實體類新建好如下:

public class ImageModel:BaseEntity
{
///

/// 用戶Id
///

public int ID { get; set; }
///

///身份證正面相對路徑
///

public string IDProofFront { get; set; }
///

///身份證背面相對路徑
///

public string IDProofBack { get; set; }
}

其中 我們將身份信息實體繼承自BaseEntity,我們看看BaseEntity裡面是什麼東東,代碼如下:

public abstract partial class BaseEntity
{

public override bool Equals(object obj)
{
return Equals(obj as BaseEntity);
}

private Type GetUnproxiedType
{
return GetType;
}

public virtual bool Equals(BaseEntity other)
{
if (other == null)
return false;

if (ReferenceEquals(this, other))
return true;
return false;
}

public override int GetHashCode
{
return base.GetHashCode;
}

public static bool operator ==(BaseEntity x, BaseEntity y)
{
return Equals(x, y);
}

public static bool operator !=(BaseEntity x, BaseEntity y)
{
return !(x == y);
}
}

這裡,我們將BaseEntity定義成一個抽象類,裡面包含一些靜態方法和重載方法

======================回到HTML=======

我們先回過頭來講頁面,上面演示的是一個很簡單的單頁面,HTML代碼如下:


 用戶上傳的文件
步驟: (上傳資料必須是bmp,gif,jpg,jpeg,png類型,不能大於2M)

  1. 先按『選擇』鍵選擇上傳文件;
  2. 按『上傳』鍵上傳文件;
  3. 按『保存』鍵保存文件;

身份證正面

@if (Model == null || Model.ID == null || string.IsNullOrEmpty(Model.IDProofFront))
{



}
else
{



}
@Html.HiddenFor(m => m.IDProofFront)
@Html.HiddenFor(m => m.ID)

上傳
身份證背面 @if (Model == null || Model.ID == null || string.IsNullOrEmpty(Model.IDProofBack))
{



}
else
{



}
@Html.HiddenFor(m => m.IDProofBack)
上傳

返回

現在我們看頁面將會毫無樣式,所以我們先引用下樣式,這裡引用了bootstrap 和一個 style2.css ,引入樣式後 界面如下:

C# ftp 圖片上傳多快好省

/*!
* FileInput Chinese Translations
*
* This file must be loaded after "fileinput.js". Patterns in braces "{}", or
* any HTML markup tags in the messages must not be converted or translated.
*
* @see http://github.com/kartik-v/bootstrap-fileinput
* @author kangqf
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
(function ($) {
"use strict";

$.fn.fileinputLocales["zh"] = {
fileSingle: "文件",
filePlural: "個文件",
browseLabel: "選擇 …",
removeLabel: "移除",
removeTitle: "清除選中文件",
cancelLabel: "取消",
cancelTitle: "取消進行中的上傳",
uploadLabel: "上傳",
uploadTitle: "上傳選中文件",
msgNo: "沒有",
msgNoFilesSelected: "",
msgCancelled: "取消",
msgZoomModalHeading: "詳細預覽",
msgSizeTooSmall: "File "{name}" ({size} KB) is too small and must be larger than {minSize} KB.",
msgSizeTooLarge: "文件 "{name}" ({size} KB) 超過了允許大小 {maxSize} KB.",
msgFilesTooLess: "你必須選擇最少 {n} {files} 來上傳. ",
msgFilesTooMany: "選擇的上傳文件個數 ({n}) 超出最大文件的限制個數 {m}.",
msgFileNotFound: "文件 "{name}" 未找到!",
msgFileSecured: "安全限制,為了防止讀取文件 "{name}".",
msgFileNotReadable: "文件 "{name}" 不可讀.",
msgFilePreviewAborted: "取消 "{name}" 的預覽.",
msgFilePreviewError: "讀取 "{name}" 時出現了一個錯誤.",
msgInvalidFileName: "Invalid or unsupported characters in file name "{name}".",
msgInvalidFileType: "不正確的類型 "{name}". 只支持 "{types}" 類型的文件.",
msgInvalidFileExtension: "不正確的文件擴展名 "{name}". 只支持 "{extensions}" 的文件擴展名.",
msgFileTypes: {
"image": "image",
"html": "HTML",
"text": "text",
"video": "video",
"audio": "audio",
"flash": "flash",
"pdf": "PDF",
"object": "object"
},
msgUploadAborted: "該文件上傳被中止",
msgUploadThreshold: "Processing...",
msgUploadEmpty: "No valid data available for upload.",
msgValidationError: "驗證錯誤",
msgLoading: "載入第 {index} 文件 共 {files} …",
msgProgress: "載入第 {index} 文件 共 {files} - {name} - {percent}% 完成.",
msgSelected: "{n} {files} 選中",
msgFoldersNotAllowed: "只支持拖拽文件! 跳過 {n} 拖拽的文件夾.",
msgImageWidthSmall: "寬度的圖像文件的"{name}"的必須是至少{size}像素.",
msgImageHeightSmall: "圖像文件的"{name}"的高度必須至少為{size}像素.",
msgImageWidthLarge: "寬度的圖像文件"{name}"不能超過{size}像素.",
msgImageHeightLarge: "圖像文件"{name}"的高度不能超過{size}像素.",
msgImageResizeError: "無法獲取的圖像尺寸調整。",
msgImageResizeException: "錯誤而調整圖像大小。

{errors}

",
msgAjaxError: "Something went wrong with the {operation} operation. Please try again later!",
msgAjaxProgressError: "{operation} failed",
ajaxOperations: {
deleteThumb: "file delete",
uploadThumb: "single file upload",
uploadBatch: "batch file upload",
uploadExtra: "form data upload"
},
dropZoneTitle: "拖拽文件到這裡 …
支持多文件同時上傳",
dropZoneClickTitle: "
(或點擊{files}按鈕選擇文件)",
fileActionSettings: {
removeTitle: "刪除文件",
uploadTitle: "上傳文件",
zoomTitle: "查看詳情",
dragTitle: "移動 / 重置",
indicatorNewTitle: "沒有上傳",
indicatorSuccessTitle: "上傳",
indicatorErrorTitle: "上傳錯誤",
indicatorLoadingTitle: "上傳 ..."
},
previewZoomButtonTitles: {
prev: "預覽上一個文件",
next: "預覽下一個文件",
toggleheader: "縮放",
fullscreen: "全屏",
borderless: "無邊界模式",
close: "關閉當前預覽"
}
};
})(window.jQuery);

View Code

好了,界面大概就整成這樣子,現在需要我們實現功能了。首先用JS將上傳控制項初始化一下:

//上傳控制項初始化
function initFileUpload {
$("#uploadfile").fileinput({
//uploadExtraData: { kvId: "10" },
language: "zh", //設置語言
showUpload: false, //是否顯示上傳按鈕
uploadAsync: true, //默認非同步上傳
showRemove: false,
autoReplace: true,
maxFileCount: 1,
maxFileSize: 10240,
dropZoneTitle: "拖拽文件到這裡 …
僅限.pdf, .jpg, .jpeg, .gif",
enctype: "multipart/form-data",
fileActionSettings: { uploadClass: "hidden", zoomClass: "hidden", removeClass: "hidden" },
allowedFileExtensions: ["jpg", "png", "gif", "pdf"],//接收的文件後綴
msgFilesTooMany: "選擇上傳的文件數量({n}) 超過允許的最大數值{m}!",
uploadUrl: "/FileUpload/FileUpLoad", //上傳的地址

}).on("filebatchselected", function (event, files) {
$(".file-preview-success").remove;
})

$("#uploadfile").on("fileuploaded", function (event, data, previewId, index) {

console.log("accountData 初始化後 FileOpt" + accountData);
console.log("accountData.FileOpt " + accountData.FileOpt);
var obj = data.response;
if (obj.Status != 500 && obj.Data != undefined) {
var src = accountData.PathSrc + obj.Data.FileName;
showName = obj.Data.FileName;
//alert(showName);

var pId = accountData.PId;
var fileObj = undefined;
var field = "";
var isPdf = false;
debugger;
if (accountData.FileOpt == 1) {
fileObj = $("#IDProofFront");
//$("#PersonInfo_OldIDFile").val(obj.Data.FileName);
field = "IDProofFront";
fileObj.val(obj.Data.FileName);
} else if (accountData.FileOpt == 2) {
fileObj = $("#IDProofBack");
field = "IDProofBack";
$("#IDProofBack").val(showName);
fileObj.val(obj.Data.FileName);
}
//fileObj = $("#IDProofFront");
//$("#IDProofFront").val(obj.Data.FileName);
//field = "IDProofFront";
//fileObj.val(obj.Data.FileName);
fileObj.prev.attr("href", src);
src = isPdf == true ? "/Content/images/PDF.png" : src;
fileObj.prev.find("img").attr("src", src);
} else {
console.error(obj.Data);
}
});

$("#uploadfile").on("filesuccessremove", function (event, id) {

});
$("#uploadfile").on("fileerror", function (event, data, msg) {

});

//上傳
$(".btnFinleUP").click(function {
var fileName = $("#uploadfile").val;
var obj = document.getElementById("uploadfile");
var type = $(this).attr("data-op");
//alert("當前點擊的type是:" + type);
var fileType = $(this).attr("data-type");
var files = $("#uploadfile").fileinput("getFileStack");

if (files.length == 0) {
layer.msg("請選擇要上傳的文件", function { });
return;
}
var array = fileType.split(",");
var selectType = files[0].type.toLowerCase;
var falg = false;
for (var i = 0; i < array.length; i++) { if (selectType.indexOf(array[i]) == -1) { falg = false; } else falg = true; if (falg) break; } if (!falg) { layer.msg("只能選擇" + fileType + " 類型的文件", function { }); return; } accountData.FileOpt = type; $("#uploadfile").fileinput("upload"); }); }

View Code

然後再 載入頁面的時候調用這個初始化即可

$(function {
initFileUpload;
})FTP上傳操作

注意,再initFileUpload方法中 上傳了圖片,會自動訪問uploadUrl 這個url地址,存放圖片,我們先看看這個action如何通過ftp上傳指定伺服器的。

FileUpLoad方法如下

///

/// 通過ftp上傳指定伺服器
///

///
public ActionResult FileUpLoad
{

bool flag = false;
string msg = string.Empty;
int size = Convert.ToInt16(_fileSize) * 1024 * 1024;

try
{
Dictionary fileDict = new Dictionary;
for (int i = 0; i < Request.Files.Count; i++) { HttpPostedFileBase file = Request.Files[i]; string extension = Path.GetExtension(file.FileName); string fileExtensions = _fileExtension.Split(";"); if (fileExtensions.Any(o => o.Equals(extension, StringComparison.OrdinalIgnoreCase)))
{
if (file.ContentLength <= size) { string fileName = string.Format("{0}_{1}", DateTime.Now.ToString("yyyyMMddHHmmssfff"), Path.GetFileName(file.FileName)); if (file.ContentLength <= 10 * 1024 * 1024) { byte buffer = new byte[file.ContentLength]; file.InputStream.Read(buffer, 0, file.ContentLength); flag = FileUpLoad(buffer, file.FileName, out fileName, out msg); } else//圖片壓縮有問題>>
{
var stream = ImageHelper.GetPicThumbnail(file.InputStream, 40);
byte buffer = new byte[stream.Length];
stream.Read(buffer, 0, (int)stream.Length);
flag = FileUpLoad(buffer, file.FileName, out fileName, out msg);
}
fileDict.Add(Request.Files.AllKeys[i], fileName);
}
else
{
msg = string.Format("上傳文件不能大於{0}M", _fileSize);
}
}
else
{
msg = string.Format("上傳的文件類型不正確");
}
}
return Json(new { Result = "0", MSG = "" + msg, Data = fileDict });

}
catch (Exception ex)
{
return Json(new { Result = "0", MSG = "網路異常,請稍後再試" });
}
}

View Code

其中 _fileExtension _filePath _fileSize 是分別從配置文件中讀取出來的如下:

private static string _fileExtension = ConfigurationManager.AppSettings["FileType"];
private readonly string _filePath = ConfigurationManager.AppSettings["UploadPath"];
private readonly string _fileSize = ConfigurationManager.AppSettings["FileSizem"];

方法中有一個 FileUpLoad 上傳文件的方法 如下:

///

/// 上傳文件
///

/// /// /// ///
protected bool FileUpLoad(byte[] fileBytes, string originalName, out string newFileName, out string msg)
{
msg = "";
newFileName = "";
try
{

FTPUpFile ftp = new FTPUpFile;
newFileName = ftp.UpFile(fileBytes, originalName);
if (string.IsNullOrEmpty(newFileName))
{
msg = "上傳文件時出錯!";
return false;
}
return true;
}
catch (Exception ex)
{
msg = ex.Message;
return false;
}
}

其中

FTPUpFile 是一個ftp上傳文件幫助類,大家可以直接照搬 ,代碼如下:

///

/// FTP上傳文件
///

public class FTPUpFile
{

string Filetype = ConfigurationManager.AppSettings["FileType"];
string ipaddress = ConfigurationManager.AppSettings["IPaddress"];
string Username = ConfigurationManager.AppSettings["UserName"];
string Password = ConfigurationManager.AppSettings["Password"];

///

/// FTP上傳文件
///

/// 上傳文件路徑 /// FTP伺服器的IP和埠 /// FTP伺服器下的哪個目錄 /// FTP用戶名 /// FTP密碼 public bool Upload(string filename, string ftpServerIP, string ftpPath, string ftpUserID, string ftpPassword)
{
FileInfo fileInf = new FileInfo(filename);
string uri = "ftp://" + ftpServerIP + "/" + ftpPath + "/" + fileInf.Name;

try
{
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(uri));
// ftp用戶名和密碼
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.KeepAlive = false;

// 指定執行什麼命令
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;

// 指定數據傳輸類型
reqFTP.UseBinary = true;

// 上傳文件時通知伺服器文件的大小
reqFTP.ContentLength = fileInf.Length;

//this.Invoke(InitUProgress, fileInf.Length);

// 緩衝大小設置為2kb
int buffLength = 4096;

byte buff = new byte[buffLength];
int contentLen;

// 打開一個文件流 (System.IO.FileStream) 去讀上傳的文件
FileStream fs = fileInf.OpenRead;

// 把上傳的文件寫入流
Stream strm = reqFTP.GetRequestStream;
contentLen = fs.Read(buff, 0, buffLength);
while (contentLen != 0)
{
strm.Write(buff, 0, contentLen);
contentLen = fs.Read(buff, 0, buffLength);
}

// 關閉兩個流
strm.Close;
strm.Dispose;
fs.Close;
fs.Dispose;

return true;
}
catch (Exception ex)
{

return false;
}

}

///

/// 新建目錄
///

/// /// public void MakeDir(string ftpPath, string dirName, string username, string password)
{
try
{

//實例化FTP連接
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath + dirName));

// ftp用戶名和密碼
request.Credentials = new NetworkCredential(username, password);

// 默認為true,連接不會被關閉

request.KeepAlive = false;

//指定FTP操作類型為創建目錄
request.Method = WebRequestMethods.Ftp.MakeDirectory;
//獲取FTP伺服器的響應
FtpWebResponse response = (FtpWebResponse)request.GetResponse;
response.Close;
}
catch (Exception ex)
{
//Respons
}
}

///

/// 刪除指定文件
///

/// /// /// /// public void DeleteFile(string ftpPath, string username, string password)
{
try
{
// string uri = "ftp://" + ftpServerIP + "/" + ftpPath + "/" + fileInf.Name;
//ftpPath = "ftp://192.168.1.111:2005/2012-12-05/20121206O5CATICE.docx";
//password = "111";
//username = "yuanluluoli";
//實例化FTP連接
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath));
request.Method = WebRequestMethods.Ftp.DeleteFile;
// ftp用戶名和密碼
request.Credentials = new NetworkCredential(username, password);
// 默認為true,連接不會被關閉
request.KeepAlive = false;
//獲取FTP伺服器的響應
FtpWebResponse response = (FtpWebResponse)request.GetResponse;
response.Close;
}
catch (Exception ex)
{
//Respons
}
}

///

/// 檢查目錄是否存在
///

/// 要檢查的目錄的路徑 /// 要檢查的目錄名 /// 存在返回true,否則false
public bool CheckDirectoryExist(string ftpPath, string dirName, string username, string password)
{
bool result = false;
try
{

//實例化FTP連接
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpPath));
// ftp用戶名和密碼
request.Credentials = new NetworkCredential(username, password);
request.KeepAlive = false;
//指定FTP操作類型為創建目錄
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
//獲取FTP伺服器的響應
FtpWebResponse response = (FtpWebResponse)request.GetResponse;
StreamReader sr = new StreamReader(response.GetResponseStream, Encoding.Default);
StringBuilder str = new StringBuilder;
string line = sr.ReadLine;
while (line != null)
{
str.Append(line);
str.Append("|");
line = sr.ReadLine;
}
string datas = str.ToString.Split("|");

for (int i = 0; i < datas.Length; i++) { if (datas[i].Contains("

"))
{
int index = datas[i].IndexOf("");
string name = datas[i].Substring(index + 5).Trim;
if (name == dirName)
{
result = true;
break;
}
}
}

sr.Close;
sr.Dispose;
response.Close;
}
catch (Exception)
{
return false;
}
return result;
}
///

/// 上傳文件
///

/// 文件的Byte數組 /// 文件原始名字(帶後綴名) /// 新文件名的前綴 ///
public string UpFile(byte[] buffer, string originalName, string perStr = "")
{
if (buffer == null || buffer.Length <= 0 || string.IsNullOrEmpty(originalName)) throw new ArgumentException("參數錯誤!"); string filePathstr = string.Empty; string filepathsql = null; try { string pathstr = perStr + DateTime.Now.ToString.Replace("/", "").Replace("-", "").Replace(":", "").Replace(" ", ""); string rodumlist = GeneralHelper.GetMixPwd(10);//10位隨機數 filePathstr = "~/File/" + pathstr + rodumlist + Path.GetExtension(originalName); //Stream sr = upfile.PostedFile.InputStream; //byte file = new byte[sr.Length]; //sr.Read(file, 0, file.Length); StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath(filePathstr)); sw.BaseStream.Write(buffer, 0, buffer.Length); sw.Flush; sw.Close; // file.SaveAs(HttpContext.Current.Server.MapPath(filePathstr));//把文件上傳到伺服器的絕對路徑上 bool check; string ftpPath = DateTime.Now.ToString("yyyy-MM-dd"); string uri = @"ftp://" + ipaddress + "/"; //檢查是否存在此目錄文件夾 if (CheckDirectoryExist(uri, ftpPath, Username, Password)) { //存在此文件夾就直接上傳 check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password); } else { MakeDir(uri, ftpPath, Username, Password);//創建 check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password); } //成功就更新 if (check) { filepathsql = ftpPath + "/" + pathstr + rodumlist + Path.GetExtension(originalName); } //檢查是否存在此文件 if (File.Exists(HttpContext.Current.Server.MapPath(filePathstr))) { File.Delete(HttpContext.Current.Server.MapPath(filePathstr)); } return filepathsql; } catch (Exception ex) { File.Delete(HttpContext.Current.Server.MapPath(filePathstr)); throw ex; } } ///

/// 上傳文件
/// 不修改名字及後綴名
///

/// 上傳文件的絕對路徑 ///
public string UpFile(string originalFilePath)
{
if (string.IsNullOrEmpty(originalFilePath))
throw new ArgumentException("參數錯誤!");
string filepathsql = null;
try
{
//檢查是否存在此文件
if (!File.Exists(originalFilePath))
throw new Exception("文件不存在!");

//Stream sr = upfile.PostedFile.InputStream;
//byte file = new byte[sr.Length];
//sr.Read(file, 0, file.Length);

// file.SaveAs(HttpContext.Current.Server.MapPath(filePathstr));//把文件上傳到伺服器的絕對路徑上

bool check;
string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
string uri = @"ftp://" + ipaddress + "/";
//檢查是否存在此目錄文件夾
if (CheckDirectoryExist(uri, ftpPath, Username, Password))
{
//存在此文件夾就直接上傳
check = Upload(originalFilePath, ipaddress, ftpPath, Username, Password);
}
else
{
MakeDir(uri, ftpPath, Username, Password);//創建
check = Upload(originalFilePath, ipaddress, ftpPath, Username, Password);
}
//成功就更新
if (check)
{

filepathsql = ftpPath + "/" + Path.GetFileName(originalFilePath);
}
//檢查是否存在此文件
if (File.Exists(originalFilePath))
{
File.Delete(originalFilePath);
}
return filepathsql;
}
catch (Exception ex)
{
//File.Delete(originalFilePath);
throw ex;
}
}

public string Ftp_Up(HtmlInputFile upfile)
{
//Encrypt En = new Encrypt;

string filePathstr = string.Empty;
string filepathsql = null;
try
{
string pathstr = DateTime.Now.ToString.Replace("/", "").Replace("-", "").Replace(":", "").Replace(" ", "");
string rodumlist = GeneralHelper.GetMixPwd(10);//10位隨機數
filePathstr = "~/File/" + pathstr + rodumlist + Path.GetExtension(upfile.PostedFile.FileName);
Stream sr = upfile.PostedFile.InputStream;
byte file = new byte[sr.Length];
sr.Read(file, 0, file.Length);
StreamWriter sw = new StreamWriter(HttpContext.Current.Server.MapPath(filePathstr));
sw.BaseStream.Write(file, 0, file.Length);
sw.Flush; sw.Close; sr.Flush; sr.Close;
// file.SaveAs(HttpContext.Current.Server.MapPath(filePathstr));//把文件上傳到伺服器的絕對路徑上

bool check;
string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
string uri = @"ftp://" + ipaddress + "/";
//檢查是否存在此目錄文件夾
if (CheckDirectoryExist(uri, ftpPath, Username, Password))
{

//存在此文件夾就直接上傳
check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
}
else
{
MakeDir(uri, ftpPath, Username, Password);//創建
check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
}

//成功就更新
if (check)
{

filepathsql = ftpPath + "/" + pathstr + rodumlist + Path.GetExtension(upfile.PostedFile.FileName);
}

//檢查是否存在此文件
if (File.Exists(HttpContext.Current.Server.MapPath(filePathstr)))
{
File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
}
return filepathsql;
}
catch (Exception)
{
File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
return filepathsql;
// Response.Write("");
}
}

///

/// 上傳
///

/// ///
public string Ftp_Up(HttpPostedFileBase postedFile)
{

string filePathstr = string.Empty;
string filepathsql = null;
try
{

string pathstr = DateTime.Now.ToString("yyyyMMddHHmmss");
string rodumlist = GeneralHelper.GetMixPwd(10);//10位隨機數
string filename = System.IO.Path.GetFileName(postedFile.FileName);
string eExtension = Path.GetExtension(filename);
string strLocation = HttpContext.Current.Server.MapPath("~/File/");
filePathstr = strLocation + pathstr + rodumlist + eExtension;

postedFile.SaveAs(filePathstr);

bool check;
string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
string uri = @"ftp://" + ipaddress + "/";
//檢查是否存在此目錄文件夾
if (CheckDirectoryExist(uri, ftpPath, Username, Password))
{
//存在此文件夾就直接上傳
check = Upload(filePathstr, ipaddress, ftpPath, Username, Password);
}
else
{
MakeDir(uri, ftpPath, Username, Password);//創建
check = Upload(filePathstr, ipaddress, ftpPath, Username, Password);
}

//成功就更新
if (check)
{

filepathsql = ftpPath + "/" + pathstr + rodumlist + eExtension;
}

//檢查是否存在此文件
if (File.Exists(filePathstr))
{
File.Delete(filePathstr);
}
return filepathsql;
}
catch (Exception ex)
{
//檢查是否存在此文件
if (File.Exists(filePathstr))
{
File.Delete(filePathstr);
}
return "";
// Response.Write("");
}
}

///

/// FTP下載文件在伺服器目錄
///

/// 本地保存目錄路徑和文件名稱 /// FTP目錄路徑和文件名稱 ///
public bool FileDown(string pathname, string filename)
{
string uri = "ftp://" + ipaddress + "/" + filename;
string FileName = pathname;//本地保存目錄

//創建一個文件流
FileStream fs = null;
Stream responseStream = null;
try
{
//創建一個與FTP伺服器聯繫的FtpWebRequest對象
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(new Uri(uri));

//連接登錄FTP伺服器
request.Credentials = new NetworkCredential(Username, Password);

request.KeepAlive = false;

//設置請求的方法是FTP文件下載
request.Method = WebRequestMethods.Ftp.DownloadFile;

//獲取一個請求響應對象
FtpWebResponse response = (FtpWebResponse)request.GetResponse;
//獲取請求的響應流
responseStream = response.GetResponseStream;

//判斷本地文件是否存在,如果存在,則打開和重寫本地文件

if (File.Exists(FileName))
fs = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite);

//判斷本地文件是否存在,如果不存在,則創建本地文件
else
{
fs = File.Create(FileName);
}

if (fs != null)
{

int buffer_count = 65536;
byte buffer = new byte[buffer_count];
int size = 0;
while ((size = responseStream.Read(buffer, 0, buffer_count)) > 0)
{
fs.Write(buffer, 0, size);

}
fs.Flush;
fs.Close;
responseStream.Close;
}

return true;
}
catch (Exception ex)
{
return false;
}
finally
{
if (fs != null)
fs.Close;
if (responseStream != null)
responseStream.Close;
}
}

///

/// 保存和上傳圖片
///

/// 需要上傳圖片 /// /// 文件路徑
public string SaveUploadImg(Bitmap imgtwo)
{
string filePathstr = string.Empty;
string filepathsql = null;
try
{
string pathstr = DateTime.Now.ToString.Replace("/", "").Replace("-", "").Replace(":", "").Replace(" ", "");
string rodumlist = GeneralHelper.GetMixPwd(10);//10位隨機數
filePathstr = "~/File/" + pathstr + rodumlist + ".jpg";
imgtwo.Save(HttpContext.Current.Server.MapPath(filePathstr));//把文件上傳到伺服器的絕對路徑上

bool check;
string ftpPath = DateTime.Now.ToString("yyyy-MM-dd");
string uri = @"ftp://" + ipaddress + "/";
//檢查是否存在此目錄文件夾
if (CheckDirectoryExist(uri, ftpPath, Username, Password))
{
//存在此文件夾就直接上傳
check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
}
else
{
MakeDir(uri, ftpPath, Username, Password);//創建
check = Upload(HttpContext.Current.Server.MapPath(filePathstr), ipaddress, ftpPath, Username, Password);
}

//成功就更新
if (check)
{
filepathsql = ftpPath + "/" + pathstr + rodumlist + ".jpg";
}

//檢查是否存在此文件
if (File.Exists(HttpContext.Current.Server.MapPath(filePathstr)))
{
File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
}
imgtwo.Dispose;

return filepathsql;
}
catch (Exception ex)
{
File.Delete(HttpContext.Current.Server.MapPath(filePathstr));
return filepathsql;
}
}

#region
///

/// 文件大小
///

public bool _File_Length(int ContentLength)
{
bool length = false;
int FileLen = ContentLength;
if (FileLen > 2048 * 1024 == false)//不能超過2M
{
length = true;
}
return length;
}
#endregion

//用來獲取文件類型
public bool File_PastFileName(string fileName)
{
//bmp, doc, docx, gif, jpg, jpeg, pdf, png, tif, tiff
bool isnot = true;
string ext = Path.GetExtension(fileName);
string type = Filetype.Split(";");
for (int i = 0; i < type.Length; i++) { if (type[i].ToLower == ext.ToLower) { isnot = false; break; } } return isnot; } }

View Code

值得注意的是:幫助類中也從配置文件中讀取了存放地址、文件類型、用戶名、密碼等必要信息。這個大家可以自己再配置文件中配置,配置好了如下所示:










還有一個類是圖片幫助類,代碼如下:

public class ImageHelper
{
///

/// 圖片壓縮
///

/// 原圖路徑 /// 保存路徑 /// 壓縮質量(數字越小壓縮率越高) 1-100 /// 寬度 /// 高度 ///
public static bool SavePicThumbnail(string sFile, string dFile, int flag, int dWidth = 0, int dHeight = 0)
{

System.Drawing.Image iSource = System.Drawing.Image.FromFile(sFile);
return SavePicThumbnail(dFile, flag, iSource, dWidth, dHeight);

}
///

/// 圖片壓縮
///

/// 原圖流 /// 保存路徑 /// 壓縮質量(數字越小壓縮率越高) 1-100 /// 寬度 /// 高度 ///
public static bool SavePicThumbnail(Stream stream, string dFile, int flag, int dWidth = 0, int dHeight = 0)
{

System.Drawing.Image iSource = System.Drawing.Image.FromStream(stream);
return SavePicThumbnail(dFile, flag, iSource, dWidth, dHeight);

}

#region GetPicThumbnail

public static Stream GetPicThumbnail(Stream stream ,int flag, int dWidth = 0, int dHeight = 0)
{
System.Drawing.Image iSource = System.Drawing.Image.FromStream(stream);
ImageFormat tFormat = iSource.RawFormat;
int sW = 0, sH = 0;
if (dHeight == 0 && dWidth == 0)
{
sW = iSource.Width;
sH = iSource.Height;
}
else if (dWidth != 0)
{
sW = dWidth;
sH = iSource.Height * dWidth / iSource.Width;
}
else if (dHeight != 0)
{
sH = dHeight;
sW = iSource.Width * dHeight / iSource.Height;
}
Bitmap ob = new Bitmap(sW, sH);
Graphics g = Graphics.FromImage(ob);
g.Clear(Color.WhiteSmoke);
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(iSource, new Rectangle(0, 0, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel);
g.Dispose;
//以下代碼為保存圖片時,設置壓縮質量
EncoderParameters ep = new EncoderParameters;
long qy = new long[1];
qy[0] = flag;//設置壓縮的比例1-100
EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy);
ep.Param[0] = eParam;
MemoryStream ms = new MemoryStream;
try
{
ImageCodecInfo arrayICI = ImageCodecInfo.GetImageEncoders;
ImageCodecInfo jpegICIinfo = null;
for (int x = 0; x < arrayICI.Length; x++) { if (arrayICI[x].FormatDescription.Equals("JPEG")) { jpegICIinfo = arrayICI[x]; break; } } if (jpegICIinfo != null) { ob.Save(ms, jpegICIinfo, ep);//dFile是壓縮後的新路徑 } else { ob.Save(ms, tFormat); } return stream; } catch { return null; } finally { iSource.Dispose; ob.Dispose; } } public static bool SavePicThumbnail(string dFile, int flag, System.Drawing.Image iSource, int dWidth = 0, int dHeight = 0) { ImageFormat tFormat = iSource.RawFormat; int sW = 0, sH = 0; if (dHeight == 0 && dWidth == 0) { sW = iSource.Width; sH = iSource.Height; } else if (dWidth != 0) { sW = dWidth; sH = iSource.Height * dWidth / iSource.Width; } else if (dHeight != 0) { sH = dHeight; sW = iSource.Width * dHeight / iSource.Height; } Bitmap ob = new Bitmap(sW, sH); Graphics g = Graphics.FromImage(ob); g.Clear(Color.WhiteSmoke); g.CompositingQuality = CompositingQuality.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(iSource, new Rectangle(0, 0, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel); g.Dispose; //以下代碼為保存圖片時,設置壓縮質量 EncoderParameters ep = new EncoderParameters; long qy = new long[1]; qy[0] = flag;//設置壓縮的比例1-100 EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy); ep.Param[0] = eParam; try { ImageCodecInfo arrayICI = ImageCodecInfo.GetImageEncoders; ImageCodecInfo jpegICIinfo = null; for (int x = 0; x < arrayICI.Length; x++) { if (arrayICI[x].FormatDescription.Equals("JPEG")) { jpegICIinfo = arrayICI[x]; break; } } if (jpegICIinfo != null) { ob.Save(dFile, jpegICIinfo, ep);//dFile是壓縮後的新路徑 } else { ob.Save(dFile, tFormat); } return true; } catch { return false; } finally { iSource.Dispose; ob.Dispose; } } #endregion }

View Code

然後我們通過在fileuploaded的回調函數中綁定url即可顯示上傳後的圖片,效果如下圖:

C# ftp 圖片上傳多快好省

不過這個只是上傳到ftp伺服器上了,並沒有保存到資料庫,現在我們要做的就是通過EF的方式將上傳的圖片保存到資料庫。

保存圖片

首先我們要建一個操作的介面基類,並且還要約束成BaseEntity,代碼如下

public interface IRepository where T : BaseEntity
{

///

/// 根據過濾條件,獲取記錄
///

/// /// (默認不跟蹤實體狀態)使用NoTracking的查詢會在性能方面得到改善 ///
IQueryable Find(Expression> exp = null, bool isNoTracking = true);

///

/// 根據過濾條件,獲取記錄
///

/// /// (默認不跟蹤實體狀態)使用NoTracking的查詢會在性能方面得到改善 /// ///
IQueryable Find(string whereLambda = null, bool isNoTracking = true, params object[] values);

IQueryable OtherTable where TEntity : BaseEntity;
IDbSet Set where TEntity : BaseEntity;
///

/// 判斷記錄是否存在
///

/// ///
bool IsExist(Expression> exp);
///

/// 查找單個(如果沒找到則返回為NULL)
///

/// /// (默認不跟蹤實體狀態)使用NoTracking的查詢會在性能方面得到改善 ///
T FindSingle(Expression> exp, bool isNoTracking = true);

///

/// 得到分頁記錄
///

/// The pageindex. /// The pagesize. /// 總條數 /// 條件謂詞 /// 排序,格式如:"Id"/"Id descending" IQueryable Find(int pageIndex, int pageSize, out int total, Expression> exp = null, string orderBy = "");

///

/// 得到分頁記錄
///

/// The pageindex. /// The pagesize. /// 總條數 /// 條件謂詞 /// 排序,格式如:"Id"/"Id descending" IQueryable Find(int pageIndex, int pageSize, out int total, string whereLambda = "", string orderBy = "", params object[] values);

///

/// 根據過濾條件獲取記錄數
///

int GetCount(Expression> exp = null);

///

/// 添加實體
///

/// The entities. /// 是否提交(true) ///
int Add(T entity, bool isComit = true);
///

/// 批量添加
///

/// The entities. /// 是否提交(true) int Adds(List entitis, bool isComit = true);
///

/// 更新實體(會更新實體的所有屬性)
///

/// The entities. /// 是否提交(true) ///
int Update(T entity, bool isComit = true);
///

/// 刪除實體
///

/// The entities. /// 是否提交(true) ///
int Delete(T entity, bool isComit = true);

///

/// 實現按需要只更新部分更新
/// 如:Update(u =>u.Id==1,u =>new User{Name="ok"}); ///

/// The where. /// The entity. int Update(Expression> where, Expression> entity);
///

/// 批量按條件刪除
///

/// int Delete(Expression> exp);

///

/// 對資料庫執行給定的 DDL/DML 命令。
///

/// sql /// 參數 ///
int ExecuteSqlCommand(string sql, params SqlParameter[] parameters);
///

/// 執行SQL查詢語句
///

/// ///
DbRawSqlQuery ExecuteSqlQuery(string sql);

///

/// 執行原始的sql查詢
///

/// 返回的泛型類型
/// sql /// 參數 ///
IList SqlQuery(string sql, params SqlParameter[] parameters);

///

/// 開啟一個事務
///

/// bool BeginTransaction(Func fun);

///

/// 執行SQL語句或存儲過程
/// 返回Datatable數據集
///

/// SQL語句或存儲過程 例如:exec usp_procedure /// 參數列表 ///
DataTable SqlQueryForDataTable(string sql, DbParameter[] parameters);

///

/// 返回Datatable數據集
///

/// 存儲過程名 /// 參數列表 ///
[Obsolete("此方法已過時,請改用SqlQueryForDataTable")]
DataTable ExecuteForDataTable(string proName, IDataParameter[] parameters);
}

View Code

然後需要實現這個基類介面,代碼如下:

public class BaseRepository : IRepository where T : BaseEntity
{

private DbContext Context
{
get
{
DbContext db = (DbContext)CallContext.GetData("DbContext");
if (db == null)
{
db = new DbContext;
// db.Database.Log = o => LoggingHelper.Instance.Logging(LogLevel.Debug, o);
CallContext.SetData("DbContext", db);
}
return db;
}
}

///

/// 根據過濾條件,獲取記錄
///

/// /// (默認不跟蹤實體狀態)使用NoTracking的查詢會在性能方面得到改善 ///
public IQueryable Find(Expression> exp = null, bool isNoTracking = true)
{
return Filter(exp, isNoTracking);
}

///

/// 根據過濾條件,獲取記錄
///

/// /// (默認不跟蹤實體狀態)使用NoTracking的查詢會在性能方面得到改善 /// ///
public IQueryable Find(string whereLambda = null, bool isNoTracking = true, params object[] values)
{
return Filter(whereLambda, isNoTracking, values);
}

///

/// 判斷記錄是否存在
///

/// ///
public bool IsExist(Expression> exp)
{
return Context.Set.Any(exp);
}

///

/// 查找單個(如果沒找到則返回為NULL)
///

/// /// (默認不跟蹤實體狀態)使用NoTracking的查詢會在性能方面得到改善 ///
public T FindSingle(Expression> exp, bool isNoTracking = true)
{
return Filter(exp, isNoTracking).FirstOrDefault;
}

///

/// 得到分頁記錄
///

/// The pageindex. /// The pagesize. /// 總條數 /// 條件謂詞 /// 排序,格式如:"Id"/"Id descending" public IQueryable Find(int pageIndex, int pageSize, out int total, Expression> exp = null, string orderBy = "")
{
if (pageIndex < 1) pageIndex = 1; var query = Filter(exp); if (!string.IsNullOrEmpty(orderBy)) query = query.OrderBy(orderBy); total = query.Count; ///return query.Skip(pageSize * (pageIndex - 1)).Take(pageSize); return null; } ///

/// 得到分頁記錄
///

/// The pageindex. /// The pagesize. /// 總條數 /// 條件謂詞 /// 排序,格式如:"Id"/"Id descending" public IQueryable Find(int pageIndex, int pageSize, out int total, string whereLambda = "", string orderBy = "", params object[] values)
{
if (pageIndex < 1) pageIndex = 1; var query = Filter(whereLambda); if (string.IsNullOrEmpty(orderBy)) query = query.OrderBy(orderBy); total = query.Count; // return query.Skip(pageSize * (pageIndex - 1)).Take(pageSize); return null; } ///

/// 根據過濾條件獲取記錄數
///

public int GetCount(Expression> exp = null)
{
return Filter(exp).Count;
}

///

/// 添加書體
///

/// The entities. /// 是否提交(true) ///
public int Add(T entity, bool isComit = true)
{

Context.Entry(entity).State = System.Data.Entity.EntityState.Added;
return isComit ? Context.SaveChanges : 0;
}

///

/// 批量添加
///

/// The entities. /// 是否提交(true) public int Adds(List entitis, bool isComit = true)
{
foreach (T item in entitis)
{
Context.Entry(item).State = System.Data.Entity.EntityState.Added;
}
return isComit ? Context.SaveChanges : 0;
}
///

/// 更新實體(會更新實體的所有屬性)
///

/// The entities. /// 是否提交(true) ///
public int Update(T entity, bool isComit = true)
{
Context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
return isComit ? Context.SaveChanges : 0;
}
///

/// 刪除實體
///

/// The entities. /// 是否提交(true) ///
public int Delete(T entity, bool isComit = true)
{
Context.Set.Remove(entity);
return isComit ? Context.SaveChanges : 0;
}

///

/// 實現按需要只更新部分更新
/// 如:Update(u =>u.Id==1,u =>new User{Name="ok"}); ///

/// The where. /// The entity. public int Update(Expression> where, Expression> entity)
{
return Context.Set.Where(where).Update(entity);
}

///

/// 批量按條件刪除
///

/// public int Delete(Expression> exp)
{
return Context.Set.Where(exp).Delete;
}

///

/// 對資料庫執行給定的 DDL/DML 命令。
///

/// sql /// 參數 ///
public int ExecuteSqlCommand(string sql, params SqlParameter[] parameters)
{
return Context.Database.ExecuteSqlCommand(sql, parameters);
}

///

/// 執行原始的sql查詢
///

/// 返回的泛型類型
/// sql /// 參數 ///
public IList SqlQuery(string sql, params SqlParameter[] parameters)
{
return Context.Database.SqlQuery(sql, parameters).ToList;
}

public bool BeginTransaction(Func fun)
{
using (var trans = Context.Database.BeginTransaction)
{
try
{
var result = fun;
trans.Commit;
return result;
}
catch (Exception)
{
trans.Rollback;
return false;
}

}
}

private IQueryable Filter(Expression> exp = null, bool isNoTracking = true)
{
var dbSet = Context.Set.AsQueryable;
if (exp != null)
dbSet = dbSet.Where(exp);
if (isNoTracking)
dbSet = dbSet.AsNoTracking;
return dbSet;
}

private IQueryable Filter(string whereLambda = null, bool isNoTracking = true, params object[] values)
{
var dbSet = Context.Set.AsQueryable;
if (whereLambda != null)
dbSet = dbSet.Where(whereLambda, values);
if (isNoTracking)
dbSet = dbSet.AsNoTracking;
return dbSet;
}
public IQueryable Table
{
get
{
return Find(whereLambda: null);
}
}

public IQueryable OtherTable where TEntity : BaseEntity
{
return Context.Set.AsNoTracking.AsQueryable;
}
public IDbSet Set where TEntity : BaseEntity
{
return Context.Set;
}

///

/// 執行SQL查詢語句
///

/// ///
public DbRawSqlQuery ExecuteSqlQuery(string sql)
{
try
{
return Context.Database.SqlQuery(sql);
}
catch (Exception ex)
{
throw ex;
}
}

///

/// 執行SQL語句或存儲過程
/// 返回Datatable數據集
///

/// SQL語句或存儲過程 例如:exec usp_procedure /// 參數列表 ///
public System.Data.DataTable SqlQueryForDataTable(string sql, params System.Data.Common.DbParameter[] parameters)
{
SqlConnection conn = new System.Data.SqlClient.SqlConnection;
try
{
conn = (SqlConnection)Context.Database.Connection;
if (conn.State != ConnectionState.Open)
{
conn.Open;
}
SqlCommand cmd = new SqlCommand;
StringBuilder sb = new StringBuilder(sql);
if (parameters != null && parameters.Length > 0)
{
if (sql.StartsWith("exec ", StringComparison.OrdinalIgnoreCase))
sb.AppendFormat(" {0}", string.Join(",", parameters.Select(o => o.ParameterName).ToArray));
foreach (var item in parameters)
{
cmd.Parameters.Add(item);
}
}
cmd.Connection = conn;
cmd.CommandText = sb.ToString;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataTable table = new DataTable;
adapter.Fill(table);

conn.Close;//連接需要關閉
return table;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn.State == ConnectionState.Open)
conn.Close;
}
}

///

/// 返回Datatable數據集
///

/// 存儲過程名 /// 參數列表 ///
[Obsolete("此方法已過時,請改用SqlQueryForDataTable")]
public System.Data.DataTable ExecuteForDataTable(string proName, IDataParameter[] parameters)
{
try
{
SqlConnection conn = new System.Data.SqlClient.SqlConnection;
conn.ConnectionString = Context.Database.Connection.ConnectionString;
if (conn.State != ConnectionState.Open)
{
conn.Open;
}
SqlCommand cmd = new SqlCommand(proName, conn);
cmd.CommandType = CommandType.StoredProcedure;

if (parameters != null && parameters.Length > 0)
{
foreach (var item in parameters)
{
cmd.Parameters.Add(item);
}
}
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataTable table = new DataTable;
adapter.Fill(table);
return table;
}
catch (Exception ex)
{
throw ex;
}
}
}

View Code

注意,我們在這個實現類中定義了一個私有方法,指明了資料庫訪問的上下文DbContext

DbContext類如下:

public class DbContext : System.Data.Entity.DbContext
{
static DbContext
{
//Database.SetInitializer(new CreateDatabaseIfNotExists);
}
public DbContext
: base("Name=DbContext")
{
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var typesToRegister = Assembly.GetExecutingAssembly.GetTypes
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType &&
type.BaseType.GetGenericTypeDefinition == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
}
}

View Code

我們將Name=DbContext 意思是去尋找webconfig中具有相同名稱的值 ,所以,我們在配置文件中配置該項如下:

再configuration節點下面新建



忘了說,這裡對實現類中的一些擴展方法做了延伸,新建一個DynamicQueryable類,代碼如下:

public static class DynamicQueryable
{
public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
{
return (IQueryable)Where((IQueryable)source, predicate, values);
}

public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (predicate == null) throw new ArgumentNullException("predicate");
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Where",
new Type { source.ElementType },
source.Expression, Expression.Quote(lambda)));
}

public static IQueryable Select(this IQueryable source, string selector, params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Select",
new Type { source.ElementType, lambda.Body.Type },
source.Expression, Expression.Quote(lambda)));
}
public static IQueryable Select(this IQueryable source, string selector, params object[] values)
{
return (IQueryable)Select((IQueryable)source, selector, values);
}
public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
{
return (IQueryable)OrderBy((IQueryable)source, ordering, values);
}

public static IQueryable ThenBy(this IQueryable source, string ordering, params object[] values)
{
return (IQueryable)ThenBy((IQueryable)source, ordering, values);
}

public static IQueryable ThenBy(this IQueryable source, string ordering, params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (ordering == null) throw new ArgumentNullException("ordering");
ParameterExpression parameters = new ParameterExpression {
Expression.Parameter(source.ElementType, "") };
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
IEnumerable orderings = parser.ParseOrdering;
Expression queryExpr = source.Expression;
string methodAsc = "ThenBy";
string methodDesc = "ThenByDescending";
foreach (DynamicOrdering o in orderings)
{
queryExpr = Expression.Call(
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
new Type { source.ElementType, o.Selector.Type },
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));

}
return source.Provider.CreateQuery(queryExpr);
}

public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (ordering == null) throw new ArgumentNullException("ordering");
ParameterExpression parameters = new ParameterExpression {
Expression.Parameter(source.ElementType, "") };
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
IEnumerable orderings = parser.ParseOrdering;
Expression queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (DynamicOrdering o in orderings)
{
queryExpr = Expression.Call(
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
new Type { source.ElementType, o.Selector.Type },
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return source.Provider.CreateQuery(queryExpr);
}

public static IQueryable OrderBy(this IQueryable source, string propertyName, bool ascending)
where T : class
{
Type type = typeof(T);

PropertyInfo property = type.GetProperty(propertyName);
if (property == null)
throw new ArgumentException("propertyName", "Not Exist");

ParameterExpression param = Expression.Parameter(type, "p");
Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);

string methodName = ascending ? "OrderBy" : "OrderByDescending";

MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
new Type { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));

return source.Provider.CreateQuery(resultExp);
}

public static IQueryable Take(this IQueryable source, int count)
{
if (source == null) throw new ArgumentNullException("source");
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Take",
new Type { source.ElementType },
source.Expression, Expression.Constant(count)));
}

public static IQueryable Skip(this IQueryable source, int count)
{
if (source == null) throw new ArgumentNullException("source");
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Skip",
new Type { source.ElementType },
source.Expression, Expression.Constant(count)));
}

public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
if (elementSelector == null) throw new ArgumentNullException("elementSelector");
LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values);
LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values);
return source.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "GroupBy",
new Type { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)));
}

public static bool Any(this IQueryable source)
{
if (source == null) throw new ArgumentNullException("source");
return (bool)source.Provider.Execute(
Expression.Call(
typeof(Queryable), "Any",
new Type { source.ElementType }, source.Expression));
}

public static int Count(this IQueryable source)
{
if (source == null) throw new ArgumentNullException("source");
return (int)source.Provider.Execute(
Expression.Call(
typeof(Queryable), "Count",
new Type { source.ElementType }, source.Expression));
}
}

public abstract class DynamicClass
{
public override string ToString
{
PropertyInfo props = this.GetType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
StringBuilder sb = new StringBuilder;
sb.Append("{");
for (int i = 0; i < props.Length; i++) { if (i > 0) sb.Append(", ");
sb.Append(props[i].Name);
sb.Append("=");
sb.Append(props[i].GetValue(this, null));
}
sb.Append("}");
return sb.ToString;
}
}

public class DynamicProperty
{
string name;
Type type;

public DynamicProperty(string name, Type type)
{
if (name == null) throw new ArgumentNullException("name");
if (type == null) throw new ArgumentNullException("type");
this.name = name;
this.type = type;
}

public string Name
{
get { return name; }
}

public Type Type
{
get { return type; }
}
}

public static class DynamicExpression
{
public static Expression Parse(Type resultType, string expression, params object[] values)
{
ExpressionParser parser = new ExpressionParser(null, expression, values);
return parser.Parse(resultType);
}

public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values)
{
return ParseLambda(new ParameterExpression { Expression.Parameter(itType, "") }, resultType, expression, values);
}

public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
{
ExpressionParser parser = new ExpressionParser(parameters, expression, values);
return Expression.Lambda(parser.Parse(resultType), parameters);
}

public static Expression> ParseLambda(string expression, params object[] values)
{
return (Expression>)ParseLambda(typeof(T), typeof(S), expression, values);
}

public static Type CreateClass(params DynamicProperty[] properties)
{
return ClassFactory.Instance.GetDynamicClass(properties);
}

public static Type CreateClass(IEnumerable properties)
{
return ClassFactory.Instance.GetDynamicClass(properties);
}
}

internal class DynamicOrdering
{
public Expression Selector;
public bool Ascending;
}

internal class Signature : IEquatable
{
public DynamicProperty properties;
public int hashCode;

public Signature(IEnumerable properties)
{
this.properties = properties.ToArray;
hashCode = 0;
foreach (DynamicProperty p in properties)
{
hashCode ^= p.Name.GetHashCode ^ p.Type.GetHashCode;
}
}

public override int GetHashCode
{
return hashCode;
}

public override bool Equals(object obj)
{
return obj is Signature ? Equals((Signature)obj) : false;
}

public bool Equals(Signature other)
{
if (properties.Length != other.properties.Length) return false;
for (int i = 0; i < properties.Length; i++) { if (properties[i].Name != other.properties[i].Name || properties[i].Type != other.properties[i].Type) return false; } return true; } } internal class ClassFactory { public static readonly ClassFactory Instance = new ClassFactory; static ClassFactory { } // Trigger lazy initialization of static fields ModuleBuilder module; Dictionary classes;
int classCount;
ReaderWriterLock rwLock;

private ClassFactory
{
AssemblyName name = new AssemblyName("DynamicClasses");
AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
#if ENABLE_LINQ_PARTIAL_TRUST
new ReflectionPermission(PermissionState.Unrestricted).Assert;
#endif
try
{
module = assembly.DefineDynamicModule("Module");
}
finally
{
#if ENABLE_LINQ_PARTIAL_TRUST
PermissionSet.RevertAssert;
#endif
}
classes = new Dictionary;
rwLock = new ReaderWriterLock;
}

public Type GetDynamicClass(IEnumerable properties)
{
rwLock.AcquireReaderLock(Timeout.Infinite);
try
{
Signature signature = new Signature(properties);
Type type;
if (!classes.TryGetValue(signature, out type))
{
type = CreateDynamicClass(signature.properties);
classes.Add(signature, type);
}
return type;
}
finally
{
rwLock.ReleaseReaderLock;
}
}

Type CreateDynamicClass(DynamicProperty[] properties)
{
LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);
try
{
string typeName = "DynamicClass" + (classCount + 1);
#if ENABLE_LINQ_PARTIAL_TRUST
new ReflectionPermission(PermissionState.Unrestricted).Assert;
#endif
try
{
TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |
TypeAttributes.Public, typeof(DynamicClass));
FieldInfo fields = GenerateProperties(tb, properties);
GenerateEquals(tb, fields);
GenerateGetHashCode(tb, fields);
Type result = tb.CreateType;
classCount++;
return result;
}
finally
{
#if ENABLE_LINQ_PARTIAL_TRUST
PermissionSet.RevertAssert;
#endif
}
}
finally
{
rwLock.DowngradeFromWriterLock(ref cookie);
}
}

FieldInfo GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)
{
FieldInfo fields = new FieldBuilder[properties.Length];
for (int i = 0; i < properties.Length; i++) { DynamicProperty dp = properties[i]; FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private); PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null); MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, dp.Type, Type.EmptyTypes); ILGenerator genGet = mbGet.GetILGenerator; genGet.Emit(OpCodes.Ldarg_0); genGet.Emit(OpCodes.Ldfld, fb); genGet.Emit(OpCodes.Ret); MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new Type[] { dp.Type }); ILGenerator genSet = mbSet.GetILGenerator; genSet.Emit(OpCodes.Ldarg_0); genSet.Emit(OpCodes.Ldarg_1); genSet.Emit(OpCodes.Stfld, fb); genSet.Emit(OpCodes.Ret); pb.SetGetMethod(mbGet); pb.SetSetMethod(mbSet); fields[i] = fb; } return fields; } void GenerateEquals(TypeBuilder tb, FieldInfo[] fields) { MethodBuilder mb = tb.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(bool), new Type { typeof(object) }); ILGenerator gen = mb.GetILGenerator; LocalBuilder other = gen.DeclareLocal(tb); Label next = gen.DefineLabel; gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Isinst, tb); gen.Emit(OpCodes.Stloc, other); gen.Emit(OpCodes.Ldloc, other); gen.Emit(OpCodes.Brtrue_S, next); gen.Emit(OpCodes.Ldc_I4_0); gen.Emit(OpCodes.Ret); gen.MarkLabel(next); foreach (FieldInfo field in fields) { Type ft = field.FieldType; Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
next = gen.DefineLabel;
gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.Emit(OpCodes.Ldloc, other);
gen.Emit(OpCodes.Ldfld, field);
gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null);
gen.Emit(OpCodes.Brtrue_S, next);
gen.Emit(OpCodes.Ldc_I4_0);
gen.Emit(OpCodes.Ret);
gen.MarkLabel(next);
}
gen.Emit(OpCodes.Ldc_I4_1);
gen.Emit(OpCodes.Ret);
}

void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields)
{
MethodBuilder mb = tb.DefineMethod("GetHashCode",
MethodAttributes.Public | MethodAttributes.ReuseSlot |
MethodAttributes.Virtual | MethodAttributes.HideBySig,
typeof(int), Type.EmptyTypes);
ILGenerator gen = mb.GetILGenerator;
gen.Emit(OpCodes.Ldc_I4_0);
foreach (FieldInfo field in fields)
{
Type ft = field.FieldType;
Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null);
gen.Emit(OpCodes.Xor);
}
gen.Emit(OpCodes.Ret);
}
}

public sealed class ParseException : Exception
{
int position;

public ParseException(string message, int position)
: base(message)
{
this.position = position;
}

public int Position
{
get { return position; }
}

public override string ToString
{
return string.Format(Res.ParseExceptionFormat, Message, position);
}
}

internal class ExpressionParser
{
struct Token
{
public TokenId id;
public string text;
public int pos;
}

enum TokenId
{
Unknown,
End,
Identifier,
StringLiteral,
IntegerLiteral,
RealLiteral,
Exclamation,
Percent,
Amphersand,
OpenParen,
CloseParen,
Asterisk,
Plus,
Comma,
Minus,
Dot,
Slash,
Colon,
LessThan,
Equal,
GreaterThan,
Question,
OpenBracket,
CloseBracket,
Bar,
ExclamationEqual,
DoubleAmphersand,
LessThanEqual,
LessGreater,
DoubleEqual,
GreaterThanEqual,
DoubleBar
}

interface ILogicalSignatures
{
void F(bool x, bool y);
void F(bool? x, bool? y);
}

interface IArithmeticSignatures
{
void F(int x, int y);
void F(uint x, uint y);
void F(long x, long y);
void F(ulong x, ulong y);
void F(float x, float y);
void F(double x, double y);
void F(decimal x, decimal y);
void F(int? x, int? y);
void F(uint? x, uint? y);
void F(long? x, long? y);
void F(ulong? x, ulong? y);
void F(float? x, float? y);
void F(double? x, double? y);
void F(decimal? x, decimal? y);
}

interface IRelationalSignatures : IArithmeticSignatures
{
void F(string x, string y);
void F(char x, char y);
void F(DateTime x, DateTime y);
void F(TimeSpan x, TimeSpan y);
void F(char? x, char? y);
void F(DateTime? x, DateTime? y);
void F(TimeSpan? x, TimeSpan? y);
}

interface IEqualitySignatures : IRelationalSignatures
{
void F(bool x, bool y);
void F(bool? x, bool? y);
}

interface IAddSignatures : IArithmeticSignatures
{
void F(DateTime x, TimeSpan y);
void F(TimeSpan x, TimeSpan y);
void F(DateTime? x, TimeSpan? y);
void F(TimeSpan? x, TimeSpan? y);
}

interface ISubtractSignatures : IAddSignatures
{
void F(DateTime x, DateTime y);
void F(DateTime? x, DateTime? y);
}

interface INegationSignatures
{
void F(int x);
void F(long x);
void F(float x);
void F(double x);
void F(decimal x);
void F(int? x);
void F(long? x);
void F(float? x);
void F(double? x);
void F(decimal? x);
}

interface INotSignatures
{
void F(bool x);
void F(bool? x);
}

interface IEnumerableSignatures
{
void Where(bool predicate);
void Any;
void Any(bool predicate);
void All(bool predicate);
void Count;
void Count(bool predicate);
void Min(object selector);
void Max(object selector);
void Sum(int selector);
void Sum(int? selector);
void Sum(long selector);
void Sum(long? selector);
void Sum(float selector);
void Sum(float? selector);
void Sum(double selector);
void Sum(double? selector);
void Sum(decimal selector);
void Sum(decimal? selector);
void Average(int selector);
void Average(int? selector);
void Average(long selector);
void Average(long? selector);
void Average(float selector);
void Average(float? selector);
void Average(double selector);
void Average(double? selector);
void Average(decimal selector);
void Average(decimal? selector);
}

static readonly Type predefinedTypes = {
typeof(Object),
typeof(Boolean),
typeof(Char),
typeof(String),
typeof(SByte),
typeof(Byte),
typeof(Int16),
typeof(UInt16),
typeof(Int32),
typeof(UInt32),
typeof(Int64),
typeof(UInt64),
typeof(Single),
typeof(Double),
typeof(Decimal),
typeof(DateTime),
typeof(TimeSpan),
typeof(Guid),
typeof(Math),
typeof(Convert)
};

static readonly Expression trueLiteral = Expression.Constant(true);
static readonly Expression falseLiteral = Expression.Constant(false);
static readonly Expression nullLiteral = Expression.Constant(null);

static readonly string keywordIt = "it";
static readonly string keywordIif = "iif";
static readonly string keywordNew = "new";

static Dictionary keywords;

Dictionary symbols;
IDictionary externals;
Dictionary literals;
ParameterExpression it;
string text;
int textPos;
int textLen;
char ch;
Token token;

public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
{
if (expression == null) throw new ArgumentNullException("expression");
if (keywords == null) keywords = CreateKeywords;
symbols = new Dictionary(StringComparer.OrdinalIgnoreCase);
literals = new Dictionary;
if (parameters != null) ProcessParameters(parameters);
if (values != null) ProcessValues(values);
text = expression;
textLen = text.Length;
SetTextPos(0);
NextToken;
}

void ProcessParameters(ParameterExpression[] parameters)
{
foreach (ParameterExpression pe in parameters)
if (!String.IsNullOrEmpty(pe.Name))
AddSymbol(pe.Name, pe);
if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))
it = parameters[0];
}

void ProcessValues(object[] values)
{
for (int i = 0; i < values.Length; i++) { object value = values[i]; if (i == values.Length - 1 && value is IDictionary)
{
externals = (IDictionary)value;
}
else
{
AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value);
}
}
}

void AddSymbol(string name, object value)
{
if (symbols.ContainsKey(name))
throw ParseError(Res.DuplicateIdentifier, name);
symbols.Add(name, value);
}

public Expression Parse(Type resultType)
{
int exprPos = token.pos;
Expression expr = ParseExpression;
if (resultType != null)
if ((expr = PromoteExpression(expr, resultType, true)) == null)
throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));
ValidateToken(TokenId.End, Res.SyntaxError);
return expr;
}

#pragma warning disable 0219
public IEnumerable ParseOrdering
{
List orderings = new List;
while (true)
{
Expression expr = ParseExpression;
bool ascending = true;
if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))
{
NextToken;
}
else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))
{
NextToken;
ascending = false;
}
orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending });
if (token.id != TokenId.Comma) break;
NextToken;
}
ValidateToken(TokenId.End, Res.SyntaxError);
return orderings;
}
#pragma warning restore 0219

// ?: operator
Expression ParseExpression
{
int errorPos = token.pos;
Expression expr = ParseLogicalOr;
if (token.id == TokenId.Question)
{
NextToken;
Expression expr1 = ParseExpression;
ValidateToken(TokenId.Colon, Res.ColonExpected);
NextToken;
Expression expr2 = ParseExpression;
expr = GenerateConditional(expr, expr1, expr2, errorPos);
}
return expr;
}

// ||, or operator
Expression ParseLogicalOr
{
Expression left = ParseLogicalAnd;
while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))
{
Token op = token;
NextToken;
Expression right = ParseLogicalAnd;
CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
left = Expression.OrElse(left, right);
}
return left;
}

// &&, and operator
Expression ParseLogicalAnd
{
Expression left = ParseComparison;
while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
{
Token op = token;
NextToken;
Expression right = ParseComparison;
CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
left = Expression.AndAlso(left, right);
}
return left;
}

// =, ==, !=, <>, >, >=, <, <= operators Expression ParseComparison { Expression left = ParseAdditive; while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual || token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater || token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual || token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual) { Token op = token; NextToken; Expression right = ParseAdditive; bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual || op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater; if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType) { if (left.Type != right.Type) { if (left.Type.IsAssignableFrom(right.Type)) { right = Expression.Convert(right, left.Type); } else if (right.Type.IsAssignableFrom(left.Type)) { left = Expression.Convert(left, right.Type); } else { throw IncompatibleOperandsError(op.text, left, right, op.pos); } } } else if (IsEnumType(left.Type) || IsEnumType(right.Type)) { if (left.Type != right.Type) { Expression e; if ((e = PromoteExpression(right, left.Type, true)) != null) { right = e; } else if ((e = PromoteExpression(left, right.Type, true)) != null) { left = e; } else { throw IncompatibleOperandsError(op.text, left, right, op.pos); } } } else { CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), op.text, ref left, ref right, op.pos); } switch (op.id) { case TokenId.Equal: case TokenId.DoubleEqual: left = GenerateEqual(left, right); break; case TokenId.ExclamationEqual: case TokenId.LessGreater: left = GenerateNotEqual(left, right); break; case TokenId.GreaterThan: left = GenerateGreaterThan(left, right); break; case TokenId.GreaterThanEqual: left = GenerateGreaterThanEqual(left, right); break; case TokenId.LessThan: left = GenerateLessThan(left, right); break; case TokenId.LessThanEqual: left = GenerateLessThanEqual(left, right); break; } } return left; } // +, -, & operators Expression ParseAdditive { Expression left = ParseMultiplicative; while (token.id == TokenId.Plus || token.id == TokenId.Minus || token.id == TokenId.Amphersand) { Token op = token; NextToken; Expression right = ParseMultiplicative; switch (op.id) { case TokenId.Plus: if (left.Type == typeof(string) || right.Type == typeof(string)) goto case TokenId.Amphersand; CheckAndPromoteOperands(typeof(IAddSignatures), op.text, ref left, ref right, op.pos); left = GenerateAdd(left, right); break; case TokenId.Minus: CheckAndPromoteOperands(typeof(ISubtractSignatures), op.text, ref left, ref right, op.pos); left = GenerateSubtract(left, right); break; case TokenId.Amphersand: left = GenerateStringConcat(left, right); break; } } return left; } // *, /, %, mod operators Expression ParseMultiplicative { Expression left = ParseUnary; while (token.id == TokenId.Asterisk || token.id == TokenId.Slash || token.id == TokenId.Percent || TokenIdentifierIs("mod")) { Token op = token; NextToken; Expression right = ParseUnary; CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.text, ref left, ref right, op.pos); switch (op.id) { case TokenId.Asterisk: left = Expression.Multiply(left, right); break; case TokenId.Slash: left = Expression.Divide(left, right); break; case TokenId.Percent: case TokenId.Identifier: left = Expression.Modulo(left, right); break; } } return left; } // -, !, not unary operators Expression ParseUnary { if (token.id == TokenId.Minus || token.id == TokenId.Exclamation || TokenIdentifierIs("not")) { Token op = token; NextToken; if (op.id == TokenId.Minus && (token.id == TokenId.IntegerLiteral || token.id == TokenId.RealLiteral)) { token.text = "-" + token.text; token.pos = op.pos; return ParsePrimary; } Expression expr = ParseUnary; if (op.id == TokenId.Minus) { CheckAndPromoteOperand(typeof(INegationSignatures), op.text, ref expr, op.pos); expr = Expression.Negate(expr); } else { CheckAndPromoteOperand(typeof(INotSignatures), op.text, ref expr, op.pos); expr = Expression.Not(expr); } return expr; } return ParsePrimary; } Expression ParsePrimary { Expression expr = ParsePrimaryStart; while (true) { if (token.id == TokenId.Dot) { NextToken; expr = ParseMemberAccess(null, expr); } else if (token.id == TokenId.OpenBracket) { expr = ParseElementAccess(expr); } else { break; } } return expr; } Expression ParsePrimaryStart { switch (token.id) { case TokenId.Identifier: return ParseIdentifier; case TokenId.StringLiteral: return ParseStringLiteral; case TokenId.IntegerLiteral: return ParseIntegerLiteral; case TokenId.RealLiteral: return ParseRealLiteral; case TokenId.OpenParen: return ParseParenExpression; default: throw ParseError(Res.ExpressionExpected); } } Expression ParseStringLiteral { ValidateToken(TokenId.StringLiteral); char quote = token.text[0]; string s = token.text.Substring(1, token.text.Length - 2); int start = 0; while (true) { int i = s.IndexOf(quote, start); if (i < 0) break; s = s.Remove(i, 1); start = i + 1; } //if (quote == """) { // if (s.Length != 1) // throw ParseError(Res.InvalidCharacterLiteral); // NextToken; // return CreateLiteral(s[0], s); //} NextToken; return CreateLiteral(s, s); } Expression ParseIntegerLiteral { ValidateToken(TokenId.IntegerLiteral); string text = token.text; if (text[0] != "-") { ulong value; if (!UInt64.TryParse(text, out value)) throw ParseError(Res.InvalidIntegerLiteral, text); NextToken; if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text); if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text); if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text); return CreateLiteral(value, text); } else { long value; if (!Int64.TryParse(text, out value)) throw ParseError(Res.InvalidIntegerLiteral, text); NextToken; if (value >= Int32.MinValue && value <= Int32.MaxValue) return CreateLiteral((int)value, text); return CreateLiteral(value, text); } } Expression ParseRealLiteral { ValidateToken(TokenId.RealLiteral); string text = token.text; object value = null; char last = text[text.Length - 1]; if (last == "F" || last == "f") { float f; if (Single.TryParse(text.Substring(0, text.Length - 1), out f)) value = f; } else { double d; if (Double.TryParse(text, out d)) value = d; } if (value == null) throw ParseError(Res.InvalidRealLiteral, text); NextToken; return CreateLiteral(value, text); } Expression CreateLiteral(object value, string text) { ConstantExpression expr = Expression.Constant(value); literals.Add(expr, text); return expr; } Expression ParseParenExpression { ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); NextToken; Expression e = ParseExpression; ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected); NextToken; return e; } Expression ParseIdentifier { ValidateToken(TokenId.Identifier); object value; if (keywords.TryGetValue(token.text, out value)) { if (value is Type) return ParseTypeAccess((Type)value); if (value == (object)keywordIt) return ParseIt; if (value == (object)keywordIif) return ParseIif; if (value == (object)keywordNew) return ParseNew; NextToken; return (Expression)value; } if (symbols.TryGetValue(token.text, out value) || externals != null && externals.TryGetValue(token.text, out value)) { Expression expr = value as Expression; if (expr == null) { expr = Expression.Constant(value); } else { LambdaExpression lambda = expr as LambdaExpression; if (lambda != null) return ParseLambdaInvocation(lambda); } NextToken; return expr; } if (it != null) return ParseMemberAccess(null, it); throw ParseError(Res.UnknownIdentifier, token.text); } Expression ParseIt { if (it == null) throw ParseError(Res.NoItInScope); NextToken; return it; } Expression ParseIif { int errorPos = token.pos; NextToken; Expression args = ParseArgumentList; if (args.Length != 3) throw ParseError(errorPos, Res.IifRequiresThreeArgs); return GenerateConditional(args[0], args[1], args[2], errorPos); } Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos) { if (test.Type != typeof(bool)) throw ParseError(errorPos, Res.FirstExprMustBeBool); if (expr1.Type != expr2.Type) { Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null; Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null; if (expr1as2 != null && expr2as1 == null) { expr1 = expr1as2; } else if (expr2as1 != null && expr1as2 == null) { expr2 = expr2as1; } else { string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null"; string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null"; if (expr1as2 != null && expr2as1 != null) throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2); throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2); } } return Expression.Condition(test, expr1, expr2); } Expression ParseNew { NextToken; ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); NextToken; List properties = new List;
List expressions = new List;
while (true)
{
int exprPos = token.pos;
Expression expr = ParseExpression;
string propName;
if (TokenIdentifierIs("as"))
{
NextToken;
propName = GetIdentifier;
NextToken;
}
else
{
MemberExpression me = expr as MemberExpression;
if (me == null) throw ParseError(exprPos, Res.MissingAsClause);
propName = me.Member.Name;
}
expressions.Add(expr);
properties.Add(new DynamicProperty(propName, expr.Type));
if (token.id != TokenId.Comma) break;
NextToken;
}
ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
NextToken;
Type type = DynamicExpression.CreateClass(properties);
MemberBinding bindings = new MemberBinding[properties.Count];
for (int i = 0; i < bindings.Length; i++) bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]); return Expression.MemberInit(Expression.New(type), bindings); } Expression ParseLambdaInvocation(LambdaExpression lambda) { int errorPos = token.pos; NextToken; Expression args = ParseArgumentList; MethodBase method; if (FindMethod(lambda.Type, "Invoke", false, args, out method) != 1) throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda); return Expression.Invoke(lambda, args); } Expression ParseTypeAccess(Type type) { int errorPos = token.pos; NextToken; if (token.id == TokenId.Question) { if (!type.IsValueType || IsNullableType(type)) throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type)); type = typeof(Nullable<>).MakeGenericType(type);
NextToken;
}
if (token.id == TokenId.OpenParen)
{
Expression args = ParseArgumentList;
MethodBase method;
switch (FindBestMethod(type.GetConstructors, args, out method))
{
case 0:
if (args.Length == 1)
return GenerateConversion(args[0], type, errorPos);
throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type));
case 1:
return Expression.New((ConstructorInfo)method, args);
default:
throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type));
}
}
ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected);
NextToken;
return ParseMemberAccess(type, null);
}

Expression GenerateConversion(Expression expr, Type type, int errorPos)
{
Type exprType = expr.Type;
if (exprType == type) return expr;
if (exprType.IsValueType && type.IsValueType)
{
if ((IsNullableType(exprType) || IsNullableType(type)) &&
GetNonNullableType(exprType) == GetNonNullableType(type))
return Expression.Convert(expr, type);
if ((IsNumericType(exprType) || IsEnumType(exprType)) &&
(IsNumericType(type)) || IsEnumType(type))
return Expression.ConvertChecked(expr, type);
}
if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) ||
exprType.IsInterface || type.IsInterface)
return Expression.Convert(expr, type);
throw ParseError(errorPos, Res.CannotConvertValue,
GetTypeName(exprType), GetTypeName(type));
}

Expression ParseMemberAccess(Type type, Expression instance)
{
if (instance != null) type = instance.Type;
int errorPos = token.pos;
string id = GetIdentifier;
NextToken;
if (token.id == TokenId.OpenParen)
{
if (instance != null && type != typeof(string))
{
Type enumerableType = FindGenericType(typeof(IEnumerable<>), type);
if (enumerableType != null)
{
Type elementType = enumerableType.GetGenericArguments[0];
return ParseAggregate(instance, elementType, id, errorPos);
}
}
Expression args = ParseArgumentList;
MethodBase mb;
switch (FindMethod(type, id, instance == null, args, out mb))
{
case 0:
throw ParseError(errorPos, Res.NoApplicableMethod,
id, GetTypeName(type));
case 1:
MethodInfo method = (MethodInfo)mb;
if (!IsPredefinedType(method.DeclaringType))
throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
if (method.ReturnType == typeof(void))
throw ParseError(errorPos, Res.MethodIsVoid,
id, GetTypeName(method.DeclaringType));
return Expression.Call(instance, (MethodInfo)method, args);
default:
throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
id, GetTypeName(type));
}
}
else
{
MemberInfo member = FindPropertyOrField(type, id, instance == null);
if (member == null)
throw ParseError(errorPos, Res.UnknownPropertyOrField,
id, GetTypeName(type));
return member is PropertyInfo ?
Expression.Property(instance, (PropertyInfo)member) :
Expression.Field(instance, (FieldInfo)member);
}
}

static Type FindGenericType(Type generic, Type type)
{
while (type != null && type != typeof(object))
{
if (type.IsGenericType && type.GetGenericTypeDefinition == generic) return type;
if (generic.IsInterface)
{
foreach (Type intfType in type.GetInterfaces)
{
Type found = FindGenericType(generic, intfType);
if (found != null) return found;
}
}
type = type.BaseType;
}
return null;
}

Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
{
ParameterExpression outerIt = it;
ParameterExpression innerIt = Expression.Parameter(elementType, "");
it = innerIt;
Expression args = ParseArgumentList;
it = outerIt;
MethodBase signature;
if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)
throw ParseError(errorPos, Res.NoApplicableAggregate, methodName);
Type typeArgs;
if (signature.Name == "Min" || signature.Name == "Max")
{
typeArgs = new Type { elementType, args[0].Type };
}
else
{
typeArgs = new Type { elementType };
}
if (args.Length == 0)
{
args = new Expression { instance };
}
else
{
args = new Expression { instance, Expression.Lambda(args[0], innerIt) };
}
return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args);
}

Expression ParseArgumentList
{
ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
NextToken;
Expression args = token.id != TokenId.CloseParen ? ParseArguments : new Expression[0];
ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
NextToken;
return args;
}

Expression ParseArguments
{
List argList = new List;
while (true)
{
argList.Add(ParseExpression);
if (token.id != TokenId.Comma) break;
NextToken;
}
return argList.ToArray;
}

Expression ParseElementAccess(Expression expr)
{
int errorPos = token.pos;
ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected);
NextToken;
Expression args = ParseArguments;
ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected);
NextToken;
if (expr.Type.IsArray)
{
if (expr.Type.GetArrayRank != 1 || args.Length != 1)
throw ParseError(errorPos, Res.CannotIndexMultiDimArray);
Expression index = PromoteExpression(args[0], typeof(int), true);
if (index == null)
throw ParseError(errorPos, Res.InvalidIndex);
return Expression.ArrayIndex(expr, index);
}
else
{
MethodBase mb;
switch (FindIndexer(expr.Type, args, out mb))
{
case 0:
throw ParseError(errorPos, Res.NoApplicableIndexer,
GetTypeName(expr.Type));
case 1:
return Expression.Call(expr, (MethodInfo)mb, args);
default:
throw ParseError(errorPos, Res.AmbiguousIndexerInvocation,
GetTypeName(expr.Type));
}
}
}

static bool IsPredefinedType(Type type)
{
foreach (Type t in predefinedTypes) if (t == type) return true;
return false;
}

static bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition == typeof(Nullable<>);
}

static Type GetNonNullableType(Type type)
{
return IsNullableType(type) ? type.GetGenericArguments[0] : type;
}

static string GetTypeName(Type type)
{
Type baseType = GetNonNullableType(type);
string s = baseType.Name;
if (type != baseType) s += "?";
return s;
}

static bool IsNumericType(Type type)
{
return GetNumericTypeKind(type) != 0;
}

static bool IsSignedIntegralType(Type type)
{
return GetNumericTypeKind(type) == 2;
}

static bool IsUnsignedIntegralType(Type type)
{
return GetNumericTypeKind(type) == 3;
}

static int GetNumericTypeKind(Type type)
{
type = GetNonNullableType(type);
if (type.IsEnum) return 0;
switch (Type.GetTypeCode(type))
{
case TypeCode.Char:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return 1;
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return 2;
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
return 3;
default:
return 0;
}
}

static bool IsEnumType(Type type)
{
return GetNonNullableType(type).IsEnum;
}

void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)
{
Expression args = new Expression { expr };
MethodBase method;
if (FindMethod(signatures, "F", false, args, out method) != 1)
throw ParseError(errorPos, Res.IncompatibleOperand,
opName, GetTypeName(args[0].Type));
expr = args[0];
}

void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)
{
Expression args = new Expression { left, right };
MethodBase method;
if (FindMethod(signatures, "F", false, args, out method) != 1)
throw IncompatibleOperandsError(opName, left, right, errorPos);
left = args[0];
right = args[1];
}

Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)
{
return ParseError(pos, Res.IncompatibleOperands,
opName, GetTypeName(left.Type), GetTypeName(right.Type));
}

MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)
{
BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
(staticAccess ? BindingFlags.Static : BindingFlags.Instance);
foreach (Type t in SelfAndBaseTypes(type))
{
MemberInfo members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,
flags, Type.FilterNameIgnoreCase, memberName);
if (members.Length != 0) return members[0];
}
return null;
}

int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)
{
BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
(staticAccess ? BindingFlags.Static : BindingFlags.Instance);
foreach (Type t in SelfAndBaseTypes(type))
{
MemberInfo members = t.FindMembers(MemberTypes.Method,
flags, Type.FilterNameIgnoreCase, methodName);
int count = FindBestMethod(members.Cast, args, out method);
if (count != 0) return count;
}
method = null;
return 0;
}

int FindIndexer(Type type, Expression[] args, out MethodBase method)
{
foreach (Type t in SelfAndBaseTypes(type))
{
MemberInfo members = t.GetDefaultMembers;
if (members.Length != 0)
{
IEnumerable methods = members.
OfType.
Select(p => (MethodBase)p.GetGetMethod).
Where(m => m != null);
int count = FindBestMethod(methods, args, out method);
if (count != 0) return count;
}
}
method = null;
return 0;
}

static IEnumerable SelfAndBaseTypes(Type type)
{
if (type.IsInterface)
{
List types = new List;
AddInterface(types, type);
return types;
}
return SelfAndBaseClasses(type);
}

static IEnumerable SelfAndBaseClasses(Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}

static void AddInterface(List types, Type type)
{
if (!types.Contains(type))
{
types.Add(type);
foreach (Type t in type.GetInterfaces) AddInterface(types, t);
}
}

class MethodData
{
public MethodBase MethodBase;
public ParameterInfo Parameters;
public Expression Args;
}

int FindBestMethod(IEnumerable methods, Expression[] args, out MethodBase method)
{
MethodData applicable = methods.
Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters }).
Where(m => IsApplicable(m, args)).
ToArray;
if (applicable.Length > 1)
{
applicable = applicable.
Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).
ToArray;
}
if (applicable.Length == 1)
{
MethodData md = applicable[0];
for (int i = 0; i < args.Length; i++) args[i] = md.Args[i]; method = md.MethodBase; } else { method = null; } return applicable.Length; } bool IsApplicable(MethodData method, Expression[] args) { if (method.Parameters.Length != args.Length) return false; Expression promotedArgs = new Expression[args.Length]; for (int i = 0; i < args.Length; i++) { ParameterInfo pi = method.Parameters[i]; if (pi.IsOut) return false; Expression promoted = PromoteExpression(args[i], pi.ParameterType, false); if (promoted == null) return false; promotedArgs[i] = promoted; } method.Args = promotedArgs; return true; } Expression PromoteExpression(Expression expr, Type type, bool exact) { if (expr.Type == type) return expr; if (expr is ConstantExpression) { ConstantExpression ce = (ConstantExpression)expr; if (ce == nullLiteral) { if (!type.IsValueType || IsNullableType(type)) return Expression.Constant(null, type); } else { string text; if (literals.TryGetValue(ce, out text)) { Type target = GetNonNullableType(type); Object value = null; switch (Type.GetTypeCode(ce.Type)) { case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: value = ParseNumber(text, target); break; case TypeCode.Double: if (target == typeof(decimal)) value = ParseNumber(text, target); break; case TypeCode.String: value = ParseEnum(text, target); break; } if (value != null) return Expression.Constant(value, type); } } } if (IsCompatibleWith(expr.Type, type)) { if (type.IsValueType || exact) return Expression.Convert(expr, type); return expr; } return null; } static object ParseNumber(string text, Type type) { switch (Type.GetTypeCode(GetNonNullableType(type))) { case TypeCode.SByte: sbyte sb; if (sbyte.TryParse(text, out sb)) return sb; break; case TypeCode.Byte: byte b; if (byte.TryParse(text, out b)) return b; break; case TypeCode.Int16: short s; if (short.TryParse(text, out s)) return s; break; case TypeCode.UInt16: ushort us; if (ushort.TryParse(text, out us)) return us; break; case TypeCode.Int32: int i; if (int.TryParse(text, out i)) return i; break; case TypeCode.UInt32: uint ui; if (uint.TryParse(text, out ui)) return ui; break; case TypeCode.Int64: long l; if (long.TryParse(text, out l)) return l; break; case TypeCode.UInt64: ulong ul; if (ulong.TryParse(text, out ul)) return ul; break; case TypeCode.Single: float f; if (float.TryParse(text, out f)) return f; break; case TypeCode.Double: double d; if (double.TryParse(text, out d)) return d; break; case TypeCode.Decimal: decimal e; if (decimal.TryParse(text, out e)) return e; break; } return null; } static object ParseEnum(string name, Type type) { if (type.IsEnum) { MemberInfo memberInfos = type.FindMembers(MemberTypes.Field, BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static, Type.FilterNameIgnoreCase, name); if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null); } return null; } static bool IsCompatibleWith(Type source, Type target) { if (source == target) return true; if (!target.IsValueType) return target.IsAssignableFrom(source); Type st = GetNonNullableType(source); Type tt = GetNonNullableType(target); if (st != source && tt == target) return false; TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st); TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt); switch (sc) { case TypeCode.SByte: switch (tc) { case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.Byte: switch (tc) { case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.Int16: switch (tc) { case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.UInt16: switch (tc) { case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.Int32: switch (tc) { case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.UInt32: switch (tc) { case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.Int64: switch (tc) { case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.UInt64: switch (tc) { case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.Single: switch (tc) { case TypeCode.Single: case TypeCode.Double: return true; } break; default: if (st == tt) return true; break; } return false; } static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2) { bool better = false; for (int i = 0; i < args.Length; i++) { int c = CompareConversions(args[i].Type, m1.Parameters[i].ParameterType, m2.Parameters[i].ParameterType); if (c < 0) return false; if (c > 0) better = true;
}
return better;
}

// Return 1 if s -> t1 is a better conversion than s -> t2
// Return -1 if s -> t2 is a better conversion than s -> t1
// Return 0 if neither conversion is better
static int CompareConversions(Type s, Type t1, Type t2)
{
if (t1 == t2) return 0;
if (s == t1) return 1;
if (s == t2) return -1;
bool t1t2 = IsCompatibleWith(t1, t2);
bool t2t1 = IsCompatibleWith(t2, t1);
if (t1t2 && !t2t1) return 1;
if (t2t1 && !t1t2) return -1;
if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return 1;
if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -1;
return 0;
}

Expression GenerateEqual(Expression left, Expression right)
{
return Expression.Equal(left, right);
}

Expression GenerateNotEqual(Expression left, Expression right)
{
return Expression.NotEqual(left, right);
}

Expression GenerateGreaterThan(Expression left, Expression right)
{
if (left.Type == typeof(string))
{
return Expression.GreaterThan(
GenerateStaticMethodCall("Compare", left, right),
Expression.Constant(0)
);
}
return Expression.GreaterThan(left, right);
}

Expression GenerateGreaterThanEqual(Expression left, Expression right)
{
if (left.Type == typeof(string))
{
return Expression.GreaterThanOrEqual(
GenerateStaticMethodCall("Compare", left, right),
Expression.Constant(0)
);
}
return Expression.GreaterThanOrEqual(left, right);
}

Expression GenerateLessThan(Expression left, Expression right)
{
if (left.Type == typeof(string))
{
return Expression.LessThan(
GenerateStaticMethodCall("Compare", left, right),
Expression.Constant(0)
);
}
return Expression.LessThan(left, right);
}

Expression GenerateLessThanEqual(Expression left, Expression right)
{
if (left.Type == typeof(string))
{
return Expression.LessThanOrEqual(
GenerateStaticMethodCall("Compare", left, right),
Expression.Constant(0)
);
}
return Expression.LessThanOrEqual(left, right);
}

Expression GenerateAdd(Expression left, Expression right)
{
if (left.Type == typeof(string) && right.Type == typeof(string))
{
return GenerateStaticMethodCall("Concat", left, right);
}
return Expression.Add(left, right);
}

Expression GenerateSubtract(Expression left, Expression right)
{
return Expression.Subtract(left, right);
}

Expression GenerateStringConcat(Expression left, Expression right)
{
return Expression.Call(
null,
typeof(string).GetMethod("Concat", new { typeof(object), typeof(object) }),
new { left, right });
}

MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
{
return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
}

Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
{
return Expression.Call(null, GetStaticMethod(methodName, left, right), new { left, right });
}

void SetTextPos(int pos)
{
textPos = pos;
ch = textPos < textLen ? text[textPos] : ""; } void NextChar { if (textPos < textLen) textPos++; ch = textPos < textLen ? text[textPos] : ""; } void NextToken { while (Char.IsWhiteSpace(ch)) NextChar; TokenId t; int tokenPos = textPos; switch (ch) { case "!": NextChar; if (ch == "=") { NextChar; t = TokenId.ExclamationEqual; } else { t = TokenId.Exclamation; } break; case "%": NextChar; t = TokenId.Percent; break; case "&": NextChar; if (ch == "&") { NextChar; t = TokenId.DoubleAmphersand; } else { t = TokenId.Amphersand; } break; case "(": NextChar; t = TokenId.OpenParen; break; case ")": NextChar; t = TokenId.CloseParen; break; case "*": NextChar; t = TokenId.Asterisk; break; case "+": NextChar; t = TokenId.Plus; break; case ",": NextChar; t = TokenId.Comma; break; case "-": NextChar; t = TokenId.Minus; break; case ".": NextChar; t = TokenId.Dot; break; case "/": NextChar; t = TokenId.Slash; break; case ":": NextChar; t = TokenId.Colon; break; case "<": NextChar; if (ch == "=") { NextChar; t = TokenId.LessThanEqual; } else if (ch == ">")
{
NextChar;
t = TokenId.LessGreater;
}
else
{
t = TokenId.LessThan;
}
break;
case "=":
NextChar;
if (ch == "=")
{
NextChar;
t = TokenId.DoubleEqual;
}
else
{
t = TokenId.Equal;
}
break;
case ">":
NextChar;
if (ch == "=")
{
NextChar;
t = TokenId.GreaterThanEqual;
}
else
{
t = TokenId.GreaterThan;
}
break;
case "?":
NextChar;
t = TokenId.Question;
break;
case "[":
NextChar;
t = TokenId.OpenBracket;
break;
case "]":
NextChar;
t = TokenId.CloseBracket;
break;
case "|":
NextChar;
if (ch == "|")
{
NextChar;
t = TokenId.DoubleBar;
}
else
{
t = TokenId.Bar;
}
break;
case """:
case """:
char quote = ch;
do
{
NextChar;
while (textPos < textLen && ch != quote) NextChar; if (textPos == textLen) throw ParseError(textPos, Res.UnterminatedStringLiteral); NextChar; } while (ch == quote); t = TokenId.StringLiteral; break; default: if (Char.IsLetter(ch) || ch == "@" || ch == "_") { do { NextChar; } while (Char.IsLetterOrDigit(ch) || ch == "_"); t = TokenId.Identifier; break; } if (Char.IsDigit(ch)) { t = TokenId.IntegerLiteral; do { NextChar; } while (Char.IsDigit(ch)); if (ch == ".") { t = TokenId.RealLiteral; NextChar; ValidateDigit; do { NextChar; } while (Char.IsDigit(ch)); } if (ch == "E" || ch == "e") { t = TokenId.RealLiteral; NextChar; if (ch == "+" || ch == "-") NextChar; ValidateDigit; do { NextChar; } while (Char.IsDigit(ch)); } if (ch == "F" || ch == "f") NextChar; break; } if (textPos == textLen) { t = TokenId.End; break; } throw ParseError(textPos, Res.InvalidCharacter, ch); } token.id = t; token.text = text.Substring(tokenPos, textPos - tokenPos); token.pos = tokenPos; } bool TokenIdentifierIs(string id) { return token.id == TokenId.Identifier && String.Equals(id, token.text, StringComparison.OrdinalIgnoreCase); } string GetIdentifier { ValidateToken(TokenId.Identifier, Res.IdentifierExpected); string id = token.text; if (id.Length > 1 && id[0] == "@") id = id.Substring(1);
return id;
}

void ValidateDigit
{
if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected);
}

void ValidateToken(TokenId t, string errorMessage)
{
if (token.id != t) throw ParseError(errorMessage);
}

void ValidateToken(TokenId t)
{
if (token.id != t) throw ParseError(Res.SyntaxError);
}

Exception ParseError(string format, params object[] args)
{
return ParseError(token.pos, format, args);
}

Exception ParseError(int pos, string format, params object[] args)
{
return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos);
}

static Dictionary CreateKeywords
{
Dictionary d = new Dictionary(StringComparer.OrdinalIgnoreCase);
d.Add("true", trueLiteral);
d.Add("false", falseLiteral);
d.Add("null", nullLiteral);
d.Add(keywordIt, keywordIt);
d.Add(keywordIif, keywordIif);
d.Add(keywordNew, keywordNew);
foreach (Type type in predefinedTypes) d.Add(type.Name, type);
return d;
}
}

static class Res
{
public const string DuplicateIdentifier = "The identifier "{0}" was defined more than once";
public const string ExpressionTypeMismatch = "Expression of type "{0}" expected";
public const string ExpressionExpected = "Expression expected";
public const string InvalidCharacterLiteral = "Character literal must contain exactly one character";
public const string InvalidIntegerLiteral = "Invalid integer literal "{0}"";
public const string InvalidRealLiteral = "Invalid real literal "{0}"";
public const string UnknownIdentifier = "Unknown identifier "{0}"";
public const string NoItInScope = "No "it" is in scope";
public const string IifRequiresThreeArgs = "The "iif" function requires three arguments";
public const string FirstExprMustBeBool = "The first expression must be of type "Boolean"";
public const string BothTypesConvertToOther = "Both of the types "{0}" and "{1}" convert to the other";
public const string NeitherTypeConvertsToOther = "Neither of the types "{0}" and "{1}" converts to the other";
public const string MissingAsClause = "Expression is missing an "as" clause";
public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression";
public const string TypeHasNoNullableForm = "Type "{0}" has no nullable form";
public const string NoMatchingConstructor = "No matching constructor in type "{0}"";
public const string AmbiguousConstructorInvocation = "Ambiguous invocation of "{0}" constructor";
public const string CannotConvertValue = "A value of type "{0}" cannot be converted to type "{1}"";
public const string NoApplicableMethod = "No applicable method "{0}" exists in type "{1}"";
public const string MethodsAreInaccessible = "Methods on type "{0}" are not accessible";
public const string MethodIsVoid = "Method "{0}" in type "{1}" does not return a value";
public const string AmbiguousMethodInvocation = "Ambiguous invocation of method "{0}" in type "{1}"";
public const string UnknownPropertyOrField = "No property or field "{0}" exists in type "{1}"";
public const string NoApplicableAggregate = "No applicable aggregate method "{0}" exists";
public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported";
public const string InvalidIndex = "Array index must be an integer expression";
public const string NoApplicableIndexer = "No applicable indexer exists in type "{0}"";
public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type "{0}"";
public const string IncompatibleOperand = "Operator "{0}" incompatible with operand type "{1}"";
public const string IncompatibleOperands = "Operator "{0}" incompatible with operand types "{1}" and "{2}"";
public const string UnterminatedStringLiteral = "Unterminated string literal";
public const string InvalidCharacter = "Syntax error "{0}"";
public const string DigitExpected = "Digit expected";
public const string SyntaxError = "Syntax error";
public const string TokenExpected = "{0} expected";
public const string ParseExceptionFormat = "{0} (at index {1})";
public const string ColonExpected = "":" expected";
public const string OpenParenExpected = ""(" expected";
public const string CloseParenOrOperatorExpected = "")" or operator expected";
public const string CloseParenOrCommaExpected = "")" or "," expected";
public const string DotOrOpenParenExpected = ""." or "(" expected";
public const string OpenBracketExpected = ""[" expected";
public const string CloseBracketOrCommaExpected = ""]" or "," expected";
public const string IdentifierExpected = "Identifier expected";
}

View Code

此時,我們需要將我們的實體和資料庫欄位映射對應起來,新建一個ImageMap類代碼如下:

public class ImageMap : EntityTypeConfiguration
{
public ImageMap
{
// Primary Key
this.HasKey(t => t.ID);

// Properties
this.Property(t => t.IDProofFront)
.HasMaxLength(100);

this.Property(t => t.IDProofBack)
.HasMaxLength(100);

// Table & Column Mappings
this.ToTable("ImageModel");
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.IDProofFront).HasColumnName("IDProofFront");
this.Property(t => t.IDProofBack).HasColumnName("IDProofBack");
}
}

其中ToTable就是指明資料庫表名,

那麼如何將上傳的圖片保存更新到資料庫呢?

接下來我們新建一個介面類IResourcesImage 並繼承操作基類 IRepository

定義一個上傳身份信息的規則如下:

bool UpdateIDProof(string IDProofFront, string IDProofBack, int pId);

接下來我們新建一個ResourcesImage 實現上述介面。代碼如下

public ResourcesImage { }
///

/// 上傳身份信息採用此種方式
///

/// /// /// ///
public bool UpdateIDProof(string IDProofFront, string IDProofBack, int pId)
{
int flag = 0;

if (IDProofFront != "" && IDProofFront != null)
{
flag = this.Update(m => m.ID == pId, u => new ImageModel { IDProofFront = IDProofFront });
if (flag == 1)
{
if (IDProofBack != "" && IDProofBack != null)
flag = this.Update(m => m.ID == pId, u => new ImageModel { IDProofBack = IDProofBack });
}
}
else
{
if (IDProofBack != "" && IDProofBack != null)
flag = this.Update(m => m.ID == pId, u => new ImageModel { IDProofBack = IDProofBack });
}
return flag == 0 ? false : true;
}

我們在中間層做一下這個操作:

private readonly IResourcesImage _resourcesImage;
public CodeBLL
{
this._resourcesImage = new ResourcesImage;
}
///

/// 根據欄位更新用戶的文件資料信息
///

/// 欄位 /// 欄位值 /// ///
public bool UpdateFileName(string IDProofFront, string IDProofBack, int pId)
{
bool flag = false;
flag = _resourcesImage.UpdateIDProof(IDProofFront, IDProofBack, pId);
return flag;
}

這樣做其實並不科學,需要手動實例化這種倉儲操作,科學的方式可以使用IOC(控制反轉).

中間層做好之後,我們只需要在HomeController中調用此方法即可,代碼如下:

C# ftp 圖片上傳多快好省

至此,我們就實現了本地通過ftp方式上傳圖片代碼,並將圖片以相對路徑保存在資料庫中,資料庫存放格式如下:

Demo下載
喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

EF之通過不同條件查找去重複
Github 開源:高效好用的對象間屬性拷貝工具:升訊威 Mapper
Java 動態載入Jar包,並使用
python每天一個小練習-強壯的密碼

TAG:科技優家 |

您可能感興趣

如何多快好省地解決三餐:國外流行的meal prep是啥
直擊MWC19上海:5G「多快好省」,華為一騎絕塵
平民生物學實驗室的福音:一種「多快好省」的DNA組裝方法TEDA
「多快好省」差個多!國產航母建造速度快、質量好、經費省
多快好省 圖片批量壓縮和轉換
如何多快好省地增肌?
美媒首曝052D改型清晰照,一舉彌補最大短板,多快好省建造中
都9102年了,看「基建狂魔」如何多快好省的造工事
感受快樂拍打,學會「多快好省」地拍出痧!
如何「多快好省」地做出一大桌子菜
多快好省!明清古刀上的馬齒焊到底是啥?
多快好省又有范!教你棒針手套+帽子的編織方法
如何多快好省的拍出倫敦婚紗照
多快好省,囤年貨,過新年,新金融與零售的雙贏
如何多快好省的練出馬甲線和腹肌
想在考場上多快好省地讀懂長難句?你只需要明白一個道理!
多快好省!就是這麼牛,雞蛋+胡蘿蔔,煎餅也瘋狂
2018婚姻法:如何儘快離婚?2種離婚方式哪個更加多快好省?
「多快好省」造航母?美海軍考慮一次性採購2艘福特級航母
心怡科技邢琳琳:數字物流要為客戶提供多快好省的價值