前言
此篇讲到的是 图片上传 功能,每个网站必定会有这样类似的功能,上传文件、上传图片等等。那么接下来,看看我们ef+uploadfile+ ftp 如何玩转上传图片吧
效果预览
具体实现
一个简单数据库 只有一个主键id,一个身份证正面路径和一个身份证背面路径三个字段。
首先呢,我们把实体类新建好如下:
public class imagemodel:baseentity
{
/// <summary>
/// 用户id
/// </summary>
public int id { get ; set ; }
/// <summary>
///身份证正面相对路径
/// </summary>
public string idprooffront { get ; set ; }
/// <summary>
///身份证背面相对路径
/// </summary>
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代码如下:
<form enctype= "multipart/form-data" id= "form" action= "/home/uploadimage" method= "post" >
<div class = "full_w" style= "margin-top: 100px; margin-left: 30%; width: 800px;" >
<div class = "h_title" > <b>用户上传的文件</b></div>
<div class = "entry" >
步骤: <span class = "red" style= "color: red" >(上传资料必须是bmp,gif,jpg,jpeg,png类型,不能大于2m)</span>
<ol>
<li>先按『选择』键选择上传文件;</li>
<li>按『上传』键上传文件;</li>
<li>按『保存』键保存文件;</li>
</ol>
</div>
<div class = "entry" >
<div class = "sep" ></div>
</div>
<div class = "entry" >
<div id= "wrapper" style= "text-align: center; position: relative;" >
<div class = "form-group" >
<input id= "uploadfile" type= "file" value= "浏览..." class = "file" name= "filename" data-upload-url= "#" style= "position: absolute; top: 0; right: 0; min-width: 100%; min-height: 100%; text-align: right; opacity: 0; background: none repeat scroll 0 0 transparent; cursor: inherit; display: block;" />
</div>
</div>
</div>
<table>
<tbody>
<tr>
<td class = "entry" >身份证正面</td>
<td>
@ if (model == null || model.id == null || string .isnullorempty(model.idprooffront))
{
<a href= "javascript:void(0);" rel= "external nofollow" rel= "external nofollow" target= "_blank" class = "winview" >
<img style= "border: none; width: 150px; height: 100px" src= "/img/noupload.png" />
</a>
}
else
{
<a href= "@(viewbag.pathsrc + model.idprooffront)" rel= "external nofollow" target= "_blank" class = "winview" >
<img style= "border: none; width: 150px; height: 100px" src= "@(viewbag.pathsrc + model.idprooffront)" />
</a>
}
@html.hiddenfor(m => m.idprooffront)
@html.hiddenfor(m => m.id)
</td>
<td>
<a href= "javascript:void(0)" rel= "external nofollow" rel= "external nofollow" class = "easyui-linkbutton btnfinleup" data-op= "1" data-type= "image" >上传</a>
</td>
</tr>
<tr>
<td class = "entry" >身份证背面</td>
<span id= "lblinfosi" style= "color: green" ></span>
<td>
@ if (model == null || model.id == null || string .isnullorempty(model.idproofback))
{
<a href= "javascript:void(0);" rel= "external nofollow" rel= "external nofollow" target= "_blank" class = "winview" >
<img style= "border: none; width: 150px; height: 100px" src= "/img/noupload.png" />
</a>
}
else
{
<a href= "@(viewbag.pathsrc + model.idproofback)" rel= "external nofollow" target= "_blank" class = "winview" >
<img style= "border: none; width: 150px; height: 100px" src= "@(viewbag.pathsrc + model.idproofback)" />
</a>
}
@html.hiddenfor(m => m.idproofback)
</td>
<td>
<a href= "javascript:void(0)" rel= "external nofollow" rel= "external nofollow" class = "easyui-linkbutton btnfinleup" data-op= "2" data-type= "image" >上传</a>
</td>
</tr>
</tbody>
</table>
<div class = "entry" >
<button class = "button" name= "btnsaveall" value= "保存" id= "btnsaveall" style= "height: 30px; width: 80px; text-align: center;" >保存</button>
<a href= "/home/index" rel= "external nofollow" style= "height: 30px; text-align: center; width: 80px; background: #ffffff; border: 1px solid #dcdcdc; border-radius: 2px; color: #444444; cursor: pointer; display: inline-block; font: 700 11px tahoma, arial, sans-serif; margin-right: 10px; padding: 7px 12px 7px 12px; position: relative; text-decoration: none; text-shadow: 0px 1px 0px #ffffff;" >返回</a>
</div>
</div>
</form>
现在我们看页面将会毫无样式,所以我们先引用下样式,这里引用了bootstrap 和一个 style2.css ,引入样式后 界面如下:
其中,关于选择框是用了一个js单独封装起来了,是代码中的zh.js,代码如下:
/*!
* 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测试数据/kartik-v/bootstrap-fileinput
* @author kangqf <kangqingfei@gmail测试数据>
*
* 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}" (<b>{size} kb</b>) is too small and must be larger than <b>{minsize} kb</b>.' ,
msgsizetoolarge: '文件 "{name}" (<b>{size} kb</b>) 超过了允许大小 <b>{maxsize} kb</b>.' ,
msgfilestooless: '你必须选择最少 <b>{n}</b> {files} 来上传. ' ,
msgfilestoomany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>.' ,
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: '错误而调整图像大小。<pre>{errors}</pre>' ,
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: '拖拽文件到这里 …<br>支持多文件同时上传' ,
dropzoneclicktitle: '<br>(或点击{files}按钮选择文件)' ,
fileactionsettings: {
removetitle: '删除文件' ,
uploadtitle: '上传文件' ,
zoomtitle: '查看详情' ,
dragtitle: '移动 / 重置' ,
indicatornewtitle: '没有上传' ,
indicatorsuccesstitle: '上传' ,
indicatorerrortitle: '上传错误' ,
indicatorloadingtitle: '上传 ...'
},
previewzoombuttontitles: {
prev: '预览上一个文件' ,
next: '预览下一个文件' ,
toggleheader: '缩放' ,
fullscreen: '全屏' ,
borderless: '无边界模式' ,
close: '关闭当前预览'
}
};
})(window.jquery);
好了,界面大概就整成这样子,现在需要我们实现功能了。首先用js将上传控件初始化一下:
//上传控件初始化
function initfileupload() {
$( "#uploadfile" ).fileinput({
//uploadextradata: { kvid: '10' },
language: 'zh' , //设置语言
showupload: false , //是否显示上传按钮
uploadasync: true , //默认异步上传
showremove: false ,
autoreplace: true ,
maxfilecount: 1,
maxfilesize: 10240,
dropzonetitle: '拖拽文件到这里 …<br>仅限.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" );
});
}
然后再 加载页面的时候调用这个初始化即可
$(function () {
initfileupload();
})
ftp上传操作
注意,再initfileupload方法中 上传了图片,会自动访问uploadurl 这个url地址,存放图片,我们先看看这个action如何通过ftp上传指定服务器的。
fileupload方法如下
/// <summary>
/// 通过ftp上传指定服务器
/// </summary>
/// <returns></returns>
public actionresult fileupload()
{
bool flag = false ;
string msg = string .empty;
int size = convert.toint16(_filesize) * 1024 * 1024;
try
{
dictionary< string , string > filedict = new dictionary< string , string >();
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 = "网络异常,请稍后再试" });
}
}
其中 _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 上传文件的方法 如下:
/// <summary>
/// 上传文件
/// </summary>
/// <param name="filebytes"></param>
/// <param name="originalname"></param>
/// <param name="msg"></param>
/// <returns></returns>
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上传文件帮助类,大家可以直接照搬 ,代码如下:
/// <summary>
/// ftp上传文件
/// </summary>
public class ftpupfile
{
string filetype = configurationmanager.appsettings[ "filetype" ];
string ipaddress = configurationmanager.appsettings[ "ipaddress" ];
string username = configurationmanager.appsettings[ "username" ];
string password = configurationmanager.appsettings[ "password" ];
/// <summary>
/// ftp上传文件
/// </summary>
/// <param name="filename">上传文件路径</param>
/// <param name="ftpserverip">ftp服务器的ip和端口</param>
/// <param name="ftppath">ftp服务器下的哪个目录</param>
/// <param name="ftpuserid">ftp用户名</param>
/// <param name="ftppassword">ftp密码</param>
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 ;
}
}
/// <summary>
/// 新建目录
/// </summary>
/// <param name="ftppath"></param>
/// <param name="dirname"></param>
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
}
}
/// <summary>
/// 删除指定文件
/// </summary>
/// <param name="ftppath"></param>
/// <param name="dirname"></param>
/// <param name="username"></param>
/// <param name="password"></param>
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
}
}
/// <summary>
/// 检查目录是否存在
/// </summary>
/// <param name="ftppath">要检查的目录的路径</param>
/// <param name="dirname">要检查的目录名</param>
/// <returns>存在返回true,否则false</returns>
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( "<dir>" ))
{
int index = datas[i].indexof( "<dir>" );
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;
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="buffer">文件的byte数组</param>
/// <param name="originalname">文件原始名字(带后缀名)</param>
/// <param name="perstr">新文件名的前缀</param>
/// <returns></returns>
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;
}
}
/// <summary>
/// 上传文件
/// 不修改名字及后缀名
/// </summary>
/// <param name="originalfilepath">上传文件的绝对路径</param>
/// <returns></returns>
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("<script>alert(" + ex.message + ");</script>");
}
}
/// <summary>
/// 上传
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
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("<script>alert(" + ex.message + ");</script>");
}
}
/// <summary>
/// ftp下载文件在服务器目录
/// </summary>
/// <param name="pathname">本地保存目录路径和文件名称</param>
/// <param name="filename">ftp目录路径和文件名称</param>
/// <returns></returns>
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();
}
}
/// <summary>
/// 保存和上传图片
/// </summary>
/// <param name="imgtwo">需要上传图片</param>
/// <param name="date"></param>
/// <returns>文件路径</returns>
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
/// <summary>
/// 文件大小
/// </summary>
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;
}
}
值得注意的是:帮助类中也从配置文件中读取了存放地址、文件类型、用户名、密码等必要信息。这个大家可以自己再配置文件中配置,配置好了如下所示:
<add key= "filesizem" value= "10" ></add>
<add key= "filetype" value= ".bmp;.gif;.jpg;.jpeg;.png;.pdf" />
<!---本地测试-->
<add key= "ipaddress" value= "路径" />
<!--ftp上传文件的帐号-->
<add key= "username" value= "账号" />
<!--ftp上传文件的密码-->
<add key= "password" value= "密码" />
<!--后台显示图片地址-->
<add key= "pathsrc" value= "路径" />
还有一个类是图片帮助类,代码如下:
public class imagehelper
{
/// <summary>
/// 图片压缩
/// </summary>
/// <param name="sfile">原图路径</param>
/// <param name="dfile">保存路径</param>
/// <param name="flag">压缩质量(数字越小压缩率越高) 1-100</param>
/// <param name="dwidth">宽度</param>
/// <param name="dheight">高度</param>
/// <returns></returns>
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);
}
/// <summary>
/// 图片压缩
/// </summary>
/// <param name="sfile">原图流</param>
/// <param name="dfile">保存路径</param>
/// <param name="flag">压缩质量(数字越小压缩率越高) 1-100</param>
/// <param name="dwidth">宽度</param>
/// <param name="dheight">高度</param>
/// <returns></returns>
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测试数据positingquality = 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测试数据positingquality = 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
}
然后我们通过在fileuploaded的回调函数中绑定url即可显示上传后的图片,效果如下图:
不过这个只是上传到ftp服务器上了,并没有保存到数据库,现在我们要做的就是通过ef的方式将上传的图片保存到数据库。
保存图片
首先我们要建一个操作的接口基类,并且还要约束成baseentity,代码如下
public interface irepository<t> where t : baseentity
{
/// <summary>
/// 根据过滤条件,获取记录
/// </summary>
/// <param name="exp"></param>
/// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>
/// <returns></returns>
iqueryable<t> find(expression<func<t, bool >> exp = null , bool isnotracking = true );
/// <summary>
/// 根据过滤条件,获取记录
/// </summary>
/// <param name="wherelambda"></param>
/// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>
/// <param name="values"></param>
/// <returns></returns>
iqueryable<t> find( string wherelambda = null , bool isnotracking = true , params object [] values);
iqueryable<tentity> othertable<tentity>() where tentity : baseentity;
idbset<tentity> set <tentity>() where tentity : baseentity;
/// <summary>
/// 判断记录是否存在
/// </summary>
/// <param name="exp"></param>
/// <returns></returns>
bool isexist(expression<func<t, bool >> exp);
/// <summary>
/// 查找单个(如果没找到则返回为null)
/// </summary>
/// <param name="exp"></param>
/// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>
/// <returns></returns>
t findsingle(expression<func<t, bool >> exp, bool isnotracking = true );
/// <summary>
/// 得到分页记录
/// </summary>
/// <param name="pageindex">the pageindex.</param>
/// <param name="pagesize">the pagesize.</param>
/// <param name="total">总条数</param>
/// <param name="exp">条件谓词</param>
/// <param name="orderby">排序,格式如:"id"/"id descending"</param>
iqueryable<t> find( int pageindex, int pagesize, out int total, expression<func<t, bool >> exp = null , string orderby = "" );
/// <summary>
/// 得到分页记录
/// </summary>
/// <param name="pageindex">the pageindex.</param>
/// <param name="pagesize">the pagesize.</param>
/// <param name="total">总条数</param>
/// <param name="wherelambda">条件谓词</param>
/// <param name="orderby">排序,格式如:"id"/"id descending"</param>
iqueryable<t> find( int pageindex, int pagesize, out int total, string wherelambda = "" , string orderby = "" , params object [] values);
/// <summary>
/// 根据过滤条件获取记录数
/// </summary>
int getcount(expression<func<t, bool >> exp = null );
/// <summary>
/// 添加实体
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
/// <returns></returns>
int add(t entity, bool iscomit = true );
/// <summary>
/// 批量添加
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
int adds(list<t> entitis, bool iscomit = true );
/// <summary>
/// 更新实体(会更新实体的所有属性)
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
/// <returns></returns>
int update(t entity, bool iscomit = true );
/// <summary>
/// 删除实体
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
/// <returns></returns>
int delete(t entity, bool iscomit = true );
/// <summary>
/// 实现按需要只更新部分更新
/// <para>如:update(u =>u.id==1,u =>new user{name="ok"});</para>
/// </summary>
/// <param name="where">the where.</param>
/// <param name="entity">the entity.</param>
int update(expression<func<t, bool >> where, expression<func<t, t>> entity);
/// <summary>
/// 批量按条件删除
/// </summary>
/// <param name="exp"></param>
int delete(expression<func<t, bool >> exp);
/// <summary>
/// 对数据库执行给定的 ddl/dml 命令。
/// </summary>
/// <param name="sql">sql</param>
/// <param name="parameters">参数</param>
/// <returns></returns>
int executesqlcommand( string sql, params sqlparameter[] parameters);
/// <summary>
/// 执行sql查询语句
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
dbrawsqlquery< int > executesqlquery( string sql);
/// <summary>
/// 执行原始的sql查询
/// </summary>
/// <typeparam name="telement">返回的泛型类型</typeparam>
/// <param name="sql">sql</param>
/// <param name="parameters">参数</param>
/// <returns></returns>
ilist<telement> sqlquery<telement>( string sql, params sqlparameter[] parameters);
/// <summary>
/// 开启一个事务
/// </summary>
/// <param name="fun"></param>
bool begintransaction(func< bool > fun);
/// <summary>
/// 执行sql语句或存储过程
/// 返回datatable数据集
/// </summary>
/// <param name="sql">sql语句或存储过程 例如:exec usp_procedure</param>
/// <param name="parameters">参数列表</param>
/// <returns></returns>
datatable sqlqueryfordatatable( string sql, dbparameter[] parameters);
/// <summary>
/// 返回datatable数据集
/// </summary>
/// <param name="proname">存储过程名</param>
/// <param name="parameters">参数列表</param>
/// <returns></returns>
[obsolete( "此方法已过时,请改用sqlqueryfordatatable" )]
datatable executefordatatable( string proname, idataparameter[] parameters);
}
然后需要实现这个基类接口,代码如下:
public class baserepository<t> : irepository<t> 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;
}
}
/// <summary>
/// 根据过滤条件,获取记录
/// </summary>
/// <param name="exp"></param>
/// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>
/// <returns></returns>
public iqueryable<t> find(expression<func<t, bool >> exp = null , bool isnotracking = true )
{
return filter(exp, isnotracking);
}
/// <summary>
/// 根据过滤条件,获取记录
/// </summary>
/// <param name="wherelambda"></param>
/// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>
/// <param name="values"></param>
/// <returns></returns>
public iqueryable<t> find( string wherelambda = null , bool isnotracking = true , params object [] values)
{
return filter(wherelambda, isnotracking, values);
}
/// <summary>
/// 判断记录是否存在
/// </summary>
/// <param name="exp"></param>
/// <returns></returns>
public bool isexist(expression<func<t, bool >> exp)
{
return context. set <t>().any(exp);
}
/// <summary>
/// 查找单个(如果没找到则返回为null)
/// </summary>
/// <param name="exp"></param>
/// <param name="isnotracking">(默认不跟踪实体状态)使用notracking的查询会在性能方面得到改善</param>
/// <returns></returns>
public t findsingle(expression<func<t, bool >> exp, bool isnotracking = true )
{
return filter(exp, isnotracking).firstordefault();
}
/// <summary>
/// 得到分页记录
/// </summary>
/// <param name="pageindex">the pageindex.</param>
/// <param name="pagesize">the pagesize.</param>
/// <param name="total">总条数</param>
/// <param name="exp">条件谓词</param>
/// <param name="orderby">排序,格式如:"id"/"id descending"</param>
public iqueryable<t> find( int pageindex, int pagesize, out int total, expression<func<t, bool >> 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 ;
}
/// <summary>
/// 得到分页记录
/// </summary>
/// <param name="pageindex">the pageindex.</param>
/// <param name="pagesize">the pagesize.</param>
/// <param name="total">总条数</param>
/// <param name="wherelambda">条件谓词</param>
/// <param name="orderby">排序,格式如:"id"/"id descending"</param>
public iqueryable<t> 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 ;
}
/// <summary>
/// 根据过滤条件获取记录数
/// </summary>
public int getcount(expression<func<t, bool >> exp = null )
{
return filter(exp).count();
}
/// <summary>
/// 添加书体
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
/// <returns></returns>
public int add(t entity, bool iscomit = true )
{
context.entry<t>(entity).state = system.data.entity.entitystate.added;
return iscomit ? context.savechanges() : 0;
}
/// <summary>
/// 批量添加
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
public int adds(list<t> entitis, bool iscomit = true )
{
foreach (t item in entitis)
{
context.entry<t>(item).state = system.data.entity.entitystate.added;
}
return iscomit ? context.savechanges() : 0;
}
/// <summary>
/// 更新实体(会更新实体的所有属性)
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
/// <returns></returns>
public int update(t entity, bool iscomit = true )
{
context.entry(entity).state = system.data.entity.entitystate.modified;
return iscomit ? context.savechanges() : 0;
}
/// <summary>
/// 删除实体
/// </summary>
/// <param name="entity">the entities.</param>
/// <param name="iscomit">是否提交(true)</param>
/// <returns></returns>
public int delete(t entity, bool iscomit = true )
{
context. set <t>().remove(entity);
return iscomit ? context.savechanges() : 0;
}
/// <summary>
/// 实现按需要只更新部分更新
/// <para>如:update(u =>u.id==1,u =>new user{name="ok"});</para>
/// </summary>
/// <param name="where">the where.</param>
/// <param name="entity">the entity.</param>
public int update(expression<func<t, bool >> where, expression<func<t, t>> entity)
{
return context. set <t>().where(where).update(entity);
}
/// <summary>
/// 批量按条件删除
/// </summary>
/// <param name="exp"></param>
public int delete(expression<func<t, bool >> exp)
{
return context. set <t>().where(exp).delete();
}
/// <summary>
/// 对数据库执行给定的 ddl/dml 命令。
/// </summary>
/// <param name="sql">sql</param>
/// <param name="parameters">参数</param>
/// <returns></returns>
public int executesqlcommand( string sql, params sqlparameter[] parameters)
{
return context.database.executesqlcommand(sql, parameters);
}
/// <summary>
/// 执行原始的sql查询
/// </summary>
/// <typeparam name="telement">返回的泛型类型</typeparam>
/// <param name="sql">sql</param>
/// <param name="parameters">参数</param>
/// <returns></returns>
public ilist<telement> sqlquery<telement>( string sql, params sqlparameter[] parameters)
{
return context.database.sqlquery<telement>(sql, parameters).tolist();
}
public bool begintransaction(func< bool > fun)
{
using (var trans = context.database.begintransaction())
{
try
{
var result = fun();
trans测试数据mit();
return result;
}
catch (exception)
{
trans.rollback();
return false ;
}
}
}
private iqueryable<t> filter(expression<func<t, bool >> exp = null , bool isnotracking = true )
{
var dbset = context. set <t>().asqueryable();
if (exp != null )
dbset = dbset.where(exp);
if (isnotracking)
dbset = dbset.asnotracking();
return dbset;
}
private iqueryable<t> filter( string wherelambda = null , bool isnotracking = true , params object [] values)
{
var dbset = context. set <t>().asqueryable();
if (wherelambda != null )
dbset = dbset.where(wherelambda, values);
if (isnotracking)
dbset = dbset.asnotracking();
return dbset;
}
public iqueryable<t> table
{
get
{
return find(wherelambda: null );
}
}
public iqueryable<tentity> othertable<tentity>() where tentity : baseentity
{
return context. set <tentity>().asnotracking().asqueryable();
}
public idbset<tentity> set <tentity>() where tentity : baseentity
{
return context. set <tentity>();
}
/// <summary>
/// 执行sql查询语句
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public dbrawsqlquery< int > executesqlquery( string sql)
{
try
{
return context.database.sqlquery< int >(sql);
}
catch (exception ex)
{
throw ex;
}
}
/// <summary>
/// 执行sql语句或存储过程
/// 返回datatable数据集
/// </summary>
/// <param name="sql">sql语句或存储过程 例如:exec usp_procedure</param>
/// <param name="parameters">参数列表</param>
/// <returns></returns>
public system.data.datatable sqlqueryfordatatable( string sql, params system.data测试数据mon.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测试数据mandtext = 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();
}
}
/// <summary>
/// 返回datatable数据集
/// </summary>
/// <param name="proname">存储过程名</param>
/// <param name="parameters">参数列表</param>
/// <returns></returns>
[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测试数据mandtype = 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;
}
}
}
注意,我们在
这个实现类中定义了一个私有方法,指明了数据库访问的上下文dbcontext
dbcontext类如下:
public class dbcontext : system.data.entity.dbcontext
{
static dbcontext()
{
//database.setinitializer(new createdatabaseifnotexists<personaldbcontext>());
}
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);
}
}
}
我们将name=dbcontext 意思是去寻找webconfig中具有相同名称的值 ,所以,我们在配置文件中配置该项如下:
再configuration节点下面新建
<connectionstrings>
<add name= "dbcontext" providername= "system.data.sqlclient" connectionstring= "server=.;database=test;uid=sa;pwd=sa;" />
</connectionstrings>
忘了说,这里对实现类中的一些扩展方法做了延伸,新建一个dynamicqueryable类,代码如下:
public static class dynamicqueryable
{
public static iqueryable<t> where<t>( this iqueryable<t> source, string predicate, params object [] values)
{
return (iqueryable<t>)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<dynamic> select<t>( this iqueryable<t> source, string selector, params object [] values)
{
return (iqueryable<dynamic>)select((iqueryable)source, selector, values);
}
public static iqueryable<t> orderby<t>( this iqueryable<t> source, string ordering, params object [] values)
{
return (iqueryable<t>)orderby((iqueryable)source, ordering, values);
}
public static iqueryable<t> thenby<t>( this iqueryable<t> source, string ordering, params object [] values)
{
return (iqueryable<t>)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<dynamicordering> 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<dynamicordering> 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<t> orderby<t>( this iqueryable<t> 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<t>(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<func<t, s>> parselambda<t, s>( string expression, params object [] values)
{
return (expression<func<t, s>>)parselambda( typeof (t), typeof (s), expression, values);
}
public static type createclass( params dynamicproperty[] properties)
{
return classfactory.instance.getdynamicclass(properties);
}
public static type createclass(ienumerable<dynamicproperty> properties)
{
return classfactory.instance.getdynamicclass(properties);
}
}
internal class dynamicordering
{
public expression selector;
public bool ascending;
}
internal class signature : iequatable<signature>
{
public dynamicproperty[] properties;
public int hashcode;
public signature(ienumerable<dynamicproperty> 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<signature, type> 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<signature, type>();
rwlock = new readerwriterlock();
}
public type getdynamicclass(ienumerable<dynamicproperty> 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< string , object > keywords;
dictionary< string , object > symbols;
idictionary< string , object > externals;
dictionary<expression, string > 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< string , object >(stringcomparer.ordinalignorecase);
literals = new dictionary<expression, string >();
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< string , object >)
{
externals = (idictionary< string , object >)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<dynamicordering> parseordering()
{
list<dynamicordering> orderings = new list<dynamicordering>();
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测试数据ma) 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<dynamicproperty> properties = new list<dynamicproperty>();
list<expression> expressions = new list<expression>();
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测试数据ma) 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<expression> arglist = new list<expression>();
while ( true )
{
arglist.add(parseexpression());
if (token.id != tokenid测试数据ma) 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<methodbase>(), 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<methodbase> methods = members.
oftype<propertyinfo>().
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<type> selfandbasetypes(type type)
{
if (type.isinterface)
{
list<type> types = new list<type>();
addinterface(types, type);
return types;
}
return selfandbaseclasses(type);
}
static ienumerable<type> selfandbaseclasses(type type)
{
while (type != null )
{
yield return type;
type = type.basetype;
}
}
static void addinterface(list<type> 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<methodbase> 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] : '\0' ;
}
void nextchar()
{
if (textpos < textlen) textpos++;
ch = textpos < textlen ? text[textpos] : '\0' ;
}
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测试数据ma;
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< string , object > createkeywords()
{
dictionary< string , object > d = new dictionary< string , object >(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" ;
}
此时,我们需要将我们的实体和数据库字段映射对应起来,新建一个imagemap类代码如下:
public class imagemap : entitytypeconfiguration<imagemodel>
{
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<imagemodel>
定义一个上传身份信息的规则如下:
bool updateidproof( string idprooffront, string idproofback, int pid);
接下来我们新建一个resourcesimage 实现上述接口。代码如下:
public resourcesimage() { }
/// <summary>
/// 上传身份信息采用此种方式
/// </summary>
/// <param name="idproofback"></param>
/// <param name="idproofback"></param>
/// <param name="pid"></param>
/// <returns></returns>
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();
}
/// <summary>
/// 根据字段更新用户的文件资料信息
/// </summary>
/// <param name="filenamefield">字段</param>
/// <param name="filenamevalue">字段值</param>
/// <param name="pid"></param>
/// <returns></returns>
public bool updatefilename( string idprooffront, string idproofback, int pid)
{
bool flag = false ;
flag = _resourcesimage.updateidproof(idprooffront, idproofback, pid);
return flag;
}
这样做其实并不科学,需要手动实例化这种仓储操作,科学的方式可以使用ioc(控制反转).
中间层做好之后,我们只需要在homecontroller中调用此方法即可,代码如下:
至此,我们就实现了本地通过ftp方式上传图片代码,并将图片以相对路径保存在数据库中,数据库存放格式如下:
demo下载
git下载
以上所述是小编给大家介绍的c# 中实现ftp 图片上传功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
原文链接:http://HdhCmsTestcnblogs测试数据/zhangxiaoyong/p/7018616.html
dy("nrwz");
查看更多关于C# 中实现ftp 图片上传功能(多快好省)的详细内容...