[转载]jQuery EasyUI ComboTree在ASP.NET MVC中的使用 - initial2013 - 博客园

mikel阅读(1189)

[转载]jQuery EasyUI ComboTree在ASP.NET MVC中的使用 – initial2013 – 博客园.

JQuery EasyUI中的ComboTree是一个比较常用的树形下拉控件,使用起来比较方便,详细使用方法见官方链接。http://www.jeasyui.com/documentation/combotree.php

但是在组织异步数据的时候感觉比较麻烦,所以今天在这里总结一些我的处理方式,有错误之处还望指正。

项目中有这样一个商品分类表,其对应的实体如下:

public partial class GoodsCategories
{
public int Id { get; set; }
public int Parentid { get; set; }
public int Theleft { get; set; }
public int Theright { get; set; }
public string CategoryName { get; set; }
public int Depth { get; set; }
public int Status { get; set; }
public string CategoryPic { get; set; }
public int Sequence { get; set; }
public string KeyWords { get; set; }
public string Description { get; set; }
public string Parentids { get; set; }
public string Arrchildids { get; set; }
public System.DateTime AddTime { get; set; }
}

其中Parentid字段就是用来维系数据之间的非线性关系的。

添加一个类JTreeNode,该类用来表示ComboTree控件需要返回的数据结构:

public class JTreeNode
{
public int id { get; set; }
public string text { get; set; }
public string state { get; set; }
public bool? Checked { get; set; }
public string iconCls { get; set; }
public object attributes { get; set; }
public JTreeNode[] children { get; set; }

public static string ConvertToJson(JTreeNode node)
{
StringBuilder sb = new StringBuilder();
sb.Append("{");

sb.AppendFormat("\"id\":{0},", node.id);

if (!string.IsNullOrWhiteSpace(node.state))
{
sb.AppendFormat("\"state\":\"{0}\",", node.state);
}
if (!string.IsNullOrWhiteSpace(node.iconCls))
{
sb.AppendFormat("\"iconCls\":\"{0}\",", node.iconCls);
}
if (node.Checked != null)
{
sb.AppendFormat("\"checked\":\"{0},\"", node.Checked);
}

// to append attributes...
if (node.attributes != null)
{
var attributesType = node.attributes.GetType();
foreach (var item in attributesType.GetProperties())
{
var value = item.GetValue(node.attributes);
if (value != null)
{
sb.AppendFormat("\"{0}\":\"{1}\",", item.Name, value);
}
}
}

//recursive append children
if (node.children != null && node.children.Length > 0)
{
StringBuilder sbChildren = new StringBuilder();
foreach (var item in node.children)
{
sbChildren.AppendFormat("{0},", ConvertToJson(item));
}

sb.AppendFormat("\"children\":[{0}],", sbChildren.ToString().TrimEnd(','));
}

sb.AppendFormat("\"text\":\"{0}\"", node.text);

sb.Append("}");

return sb.ToString();
}
}

JTreeNode类中包含一个静态的方法,用来将一个JTreeNode对象递归解析成JSON格式的字符串;

so,接下来就是要根据表GoodsCategories中的数据构造一个JTreeNode对象,控制器中的代码:

public ActionResult LoadCategoriesTree()
{
#region cache
ICache cache = new AspnetCache();
var categories = new List();

string key = "GoodsCategories";
var obj = cache.Get<List>(key);
if (obj != null)
{
categories = obj as List;
}
else
{
categories = _goodsCategoriesService.QueryOver().ToList();
cache.Add(key, categories);
}
#endregion

JTreeNode jTreeNode = new JTreeNode() { id = 0, text = "所有分类" };
this.ConstructJTreeNode(ref jTreeNode, categories);

var jsonResult = "[" + JTreeNode.ConvertToJson(jTreeNode) + "]";
return Content(jsonResult);
}

public void ConstructJTreeNode(ref JTreeNode node, List categories)
{
//find children
var pid = node.id;
var children = from i in categories where i.Parentid == pid select i;

if (children.Count() > 0)
{
List temp = new List();
foreach (var item in children)
{
var model = new JTreeNode()
{
id = item.Id,
text = item.CategoryName
};
if (item.Depth < 3)
{
model.state = "closed";
}
temp.Add(model);

}
node.children = temp.ToArray();
}

//递归遍历
if (node.children != null)
{
for (int i = 0; i < node.children.Length; i++)
{
ConstructJTreeNode(ref node.children[i], categories);
}
}

}

前端:

<script type="text/javascript">// <![CDATA[
    $(function () {
        $('#categoryid').combotree('setValue', @ViewBag.SelectedCategoryId);
    });
// ]]></script>

<select class="easyui-combotree" id="categoryid" style="width: 200px;" name="categoryid" data-options="url:'/ProductMan/LoadCategoriesTree',required:true"></select>

效果图:

[转载]在Visual Studio上开发Node.js程序(2)——远程调试及发布到Azure - 大魔王mAysWINd - 博客园

mikel阅读(957)

[转载]在Visual Studio上开发Node.js程序(2)——远程调试及发布到Azure – 大魔王mAysWINd – 博客园.

【题外话】

上次介绍了VS上开发Node.js的插件Node.js Tools for Visual Studio(NTVS),其提供了非常方便的开发和调试功能,当然很多情况下由于平台限制等原因需要在其他机器上运行程序,进而需要远程调试功能,不过 还好,NTVS提供的远程调试也非常方便。

 

【文章索引】

  1. NTVS远程调试
  2. NTVS部署到Azure

 

【一、NTVS远程调试】

NTVS提供了一个远程调试代理(Remote Debug Proxy)来实现远程调试,实际上就是不让Node.js直接运行要调试的程序,而是去运行远程调试代理,再由代理去执行程序以及与VS进行通信。

获取NTVS提供远程调试代理可以在VS里点击“工具”->“Node.js Tools”->“Remote Debugging Proxy”->“Open Container Folder”,文件夹中的RemoteDebug.js就是了。

RemoteDebug.js的参数为:

node RemoteDebug.js [args] <script to debug> [script args]

即RemoteDebug.js后跟远程调试代理的参数,然后跟待调试代码文件,最后跟待调试代码文件的参数,其中远程调试代理支持的参数有:

-localport <port num>:本机机器(NTVS所在机器)的端口号,默认为5859

-machineport <port num>:目标机器(执行程序的机器)的端口号,默认为5858

-waitforattach:当附加成功后才执行程序,默认为在目标机器上执行完脚本立即执行程序

-breakatentrypoint:从第一条入口代码处断点,即执行待调试代码时使用–debug-brk参数,默认为–debug

所以如果按默认设置的话,我们只需要把RemoteDebug.js与待执行的代码一同复制到目标机器上,然后执行如下语句就可以了:

node RemoteDebug.js server.js

如果正确的话会出现类似下图的内容:

然后在VS中选择“工具”->“附加到进程”,然后在传输里选择“Node remote debuggin (unsecured)”(如下图)。

然后在限定符里输入目标机器的地址和端口然后键入回车即可,正确的话将会在下方出现目标机器(如下图),最后点击“附加”即可。

接下来就如同在本地调试一样非常简单了。

 

【二、NTVS部署到Azure】

部署Node.js的方式有很多种,比如可以部署在Azure的网站或者云服务(Web Role方式)上等,目前NTVS只支持前者。由于Azure网站是通过IIS上的iisnode模块实现对Node.js支持的,所以除了部署程序文件 以外,还需要配置iisnode,也就是配置Web.config文件。在NTVS里,对Azure网站的支持体现在其两个Azure项目模板中,即在使 用这两个项目模板创建项目后,会自动生成配置文件,以方便部署使用。当然传统的方法比如自己上传文件或通过代码库上传文件(参见相关链接3)部署到Azure网站或者通过Web Role方式部署到云服务(参见相关链接4)等就不再赘述,微软网站上都有详细的文章。

对于NTVS创建的Azure项目,默认包括两个Web.config文件,分别是本地测试用的Web.config以及部署到Azure上的Web.cloud.config,两个可以分别修改,其中后者在上传时会自动修改名称为“Web.config”。

发布过程与其他项目一样,可以自己创建配置文件发布到指定文件夹或者FTP等等都可以。对于Windows Azure的项目,可以在发布对话框的第一步“配置文件”页面中选择“导入”按钮,然后选择“从 Windows Azure 网站导入”,然后点击登录就可以输入自己的Windows Azure的用户名和密码,登录成功后就会如下图所示,然后在下方选择要发布的Azure网站即可。

确定后VS会自动从Windows Azure上下载指定网站的配置信息,然后在第二步的“连接”中设置好连接信息,然后一路下一步就可以将项目文件部署到Azure网站上了。其中在最后一 步,可以点击“开始预览”查看或选择要上传的文件,对于Azure网站,其实只需要上传所有js文件、Web.config文件以及用到的相关静态文件即 可,bin目录及package.json和README.md都不需要上传。其中配置文件仅选择Web.config文件即可,发布时会自动使用 Web.cloud.config文件的,而如果选择Web.cloud.config文件的话,则上传后的文件名为 “Web.cloud.config”。

不过不知道为什么在我这,在发布成功后访问Azure网站会提示“You do not have permission to view this directory or page.”,就跟没有正确配置Web.config一样,所以只能重新上传一遍Web.config来解决。不过如果不修改Web.config文件 话,之后发布时仅发布js等文件就可以了。

 

【相关链接】

  1. Debugging Node.js running on Linux:http://nodejstools.codeplex.com/wikipage?title=NodeJSOnLinuxOnAzure
  2. Azure Deployment:http://nodejstools.codeplex.com/wikipage?title=AzureDeployment
  3. 构建 Node.js 网站并部署到 Windows Azure:http://www.windowsazure.cn/zh-cn/develop/nodejs/tutorials/create-a-website-(mac)/
  4. 构建 Node.js 应用程序并将其部署到 Windows Azure 云服务:http://www.windowsazure.cn/zh-cn/develop/nodejs/tutorials/getting-started/

[转载]ASP.NET中上传图片检测其是否为真实的图片 防范病毒上传至服务器 - 脑瓜子 - 博客园

mikel阅读(1348)

[转载]ASP.NET中上传图片检测其是否为真实的图片 防范病毒上传至服务器 – 脑瓜子 – 博客园.

一、需求

我们在用.net开发网站时,经常会用到图片上传,可以说是每个网站必备的,大到门户网站,电商网站,政务系统,OA系统,小到企业网站,个人网 站,博客网站,导航网站等等,都有用到图片上传,那么在客户端浏览器中上传图片,不可避免有些不法分子将病毒伪装图片文件,然后上传到我们的网站服务器, 这样造成网站崩溃。为了解决这个问题,我们在程序中先过滤,就有了接下来的文章。

二、主要代码

1、MVC中

我们就来上传一个头像,在MVC中怎么实现文件上传,请查看我的文章:【MVC系列】ASP.NET MVC中如何实现文件上传 FileUpLoad

///
/// 上传头像
///

///用户编号 /// Json(-1表示系统异常,-2表示文件不合法)
[HttpPost]
public JsonResult Upload(string userId)
{
//上传头像的路径
string folderPath = "/upload/avatar/";
//判断路径是否存在
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);//创建文件路径
HttpPostedFileBase uploadFile = Request.Files["avatars"];
if (uploadFile != null)
{
string oriFileName = uploadFile.FileName;//原始文件名
string fileName = userId + "_" + oriFileName;//文件名的格式:用户Id+文件名
uploadFile.SaveAs(Server.MapPath(folderPath + fileName));//保存到服务器
FileStream fs = new FileStream(Server.MapPath(folderPath + fileName), FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(fs);
string fileClass;
byte buffer;
byte[] b = new byte[2];
buffer = reader.ReadByte();
b[0] = buffer;
fileClass = buffer.ToString();
buffer = reader.ReadByte();
b[1] = buffer;
fileClass += buffer.ToString();
reader.Close();
fs.Close();
if (fileClass == "255216" || fileClass == "7173" || fileClass == "6677" || fileClass == "13780")
{
//255216是jpg;7173是gif;6677是BMP,13780是PNG;7790是exe,8297是rar
//Response.Write("图片可用");
//保存到数据库中
}
else
{

//Response.Write("图片非法");
FileInfo f = new FileInfo(Server.MapPath(folderPath + fileName));
f.Delete(); //删除文件
return Json(-2, JsonRequestBehavior.AllowGet);
}
return Json(Server.HtmlEncode(folderPath + fileName), JsonRequestBehavior.AllowGet);
}
return Json(-1, JsonRequestBehavior.AllowGet);

}

2、WebForm中

public void UploadFile() {
try {
HttpPostedFile postfile = Request.Files["file"];
string savepath = Server.MapPath("/upload/avatar/" + postfile.FileName);
postfile.SaveAs(savepath);
FileStream fs = new FileStream(savepath, FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(fs);
string fileClass;
byte buffer;
byte[] b = new byte[2];
buffer = reader.ReadByte();
b[0] = buffer;
fileClass = buffer.ToString();
buffer = reader.ReadByte();
b[1] = buffer;
fileClass += buffer.ToString();
reader.Close();
fs.Close();
if (fileClass == "255216" || fileClass == "7173" || fileClass == "6677" || fileClass == "13780") {
//255216是jpg;7173是gif;6677是BMP,13780是PNG;7790是exe,8297是rar
//Response.Write("图片可用");
//保存到数据库中
}
else {
//Response.Write("图片非法");
File.Delete(savepath); //删除文件
return;
}
}
catch (Exception) { //Response.Write("图片非法!");
return;
throw;
}
}

三、总结

当然,这个只是防范病毒的一个很小的举措,技术不深奥,当然我这里写的过滤有个很大的缺陷,是先把文件上传上服务器,然后再检测,这样也不安全,可 以在上传之前先检测,大家自己去实现哈。当然,上传文件要保证服务器的安全还有很多需要做的,比如在服务器中安装杀毒软件定时监测新增文件。还有硬件防火 墙很多,在这里不再阐述。

在本章中如果在MVC中文件上传无从下手的同学,可以学习到文件上传,源码中采用swfupload上传,它可以支持多文件上传。具体实现请在文章 末尾下载源代码。给大家布置一个作业,作进一步思考,怎么实现跨域或分布式上传文件。(作业的需求:网站文件服务器与Web服务器分离,用户上传文件的时 候,我们把文件存取到文件服务器中,如果文件服务器磁盘已满,该作怎么处理?当然还有如果多用户同时上传文件,对磁盘写入,我们服务器配置无法满足现有的 并发写入,我们需要考虑多文件服务器,多文件服务器,那么我们在上传文件又该做怎么处理呢?这里就涉及负载均衡和分布式)

大家有想法勇敢拍砖,欢迎拍砖,作业中的思考大家可以在评论中发表自己的看法。如果喜欢文章就顶我,也可以关注Me

结尾:这篇文章之前是发表在我的CSDN博客上的,把它移步到博客园来。CSDN的文章链接地址http://blog.csdn.net/naoguazi/article/details/8786400

最后附上全文件的源码:

MVC 版

Webform版比较简单就不上传了。

[转载]listView当中有嵌套了有onClickListener的控件时ListView自身的onItemClick无响应的解决方案 - petercao - 博客园

mikel阅读(900)

[转载]listView当中有嵌套了有onClickListener的控件时ListView自身的onItemClick无响应的解决方案 – petercao – 博客园.

Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.

Must be one of the following constant values.

Constant Value Description
beforeDescendants 0 The ViewGroup will get focus before any of its descendants.
afterDescendants 1 The ViewGroup will get focus only if none of its descendants want it.
blocksDescendants 2 The ViewGroup will block its descendants from receiving focus.

解决方案

在ListView要显示的Item的外层加上

android:descendantFocusability="blocksDescendants"

这段代码

<!--?xml version="1.0" encoding="utf-8"?-->

&nbsp;

&nbsp;

[转载]Andriod中的Context理解与分析(3)-Android开发进阶&经验分享-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(896)

[转载]Andriod中的Context理解与分析(3)-Android开发进阶&经验分享-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

需要打开一个Service的时候,ActivityManagerService会经过ApplicationThread的代理类
远程调用真正的ApplicationThread的scheduleCreateService()方法(这个里把ActivityManagerService当成了Binder客户端,
在ActivityThread中的ApplicationThread对象才是真正的Binder服务端)。


代码片段1

CreateServiceData代表一个Service的数据类
和上一篇文章一样,代码片段中的499行,调用H这个Handler实现类发消息到主线程的消息队列,然后,调用到

代码片段2

继续调用

1921行和之前获得LoadedApk 是同一个对象
继续这个方法的代码

从上面的代码可以得出:ContextImpl在Service中也是单独的

总结
从上面的代码可以看出,创建ContextImpl的过程很像,只是他们的数据对象不同罢了。并且每个类对应一个单独的ContextImpl。

类名 远程数据类 本地数据类
Application ApplicationInfo AppBindData
Activity ActivityInfo ActivityClientRecord
Service ServiceInfo CreateServiceData

并且上面的三个类使用的是同一个pacageInfo(LoadedApk)对象。

Andriod中的Context理解与分析相关链接
(1)http://www.eoeandroid.com/thread-312457-1-1.html
(2)http://www.eoeandroid.com/thread-312978-1-1.html
(3)http://www.eoeandroid.com/thread-312979-1-1.html

[转载]Andriod中的Context理解与分析(2)-Android开发进阶&经验分享-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(920)

[转载]Andriod中的Context理解与分析(2)-Android开发进阶&经验分享-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

Activity对应的Context


需要打开一个Activity的时候,ActivityManagerService会经过ApplicationThread的代理类
远程调用真正的ApplicationThread的scheduleLaunchActivity()方法(这个里把ActivityManagerService当成了Binder客户端,
在ActivityThread中的ApplicationThread对象才是真正的Binder服务端)。



代码片段1

415行创建了一个ActivityClientRecord的对象 ,这个对象用来管理Activity
417-427行,把ActivityManagerService远程传过来的参数赋值给这个对象


代码片段2

ActivityInfo是远程返回的一个包装Activity信息的实体类,实现了Parcelable接口

和上一篇文章一样,代码片段中的429行,调用H这个Handler实现类发消息到主线程的消息队列,然后,调用到

代码片段3

929行:通过getPackageInfoNoCheck()获得packegeInfo赋值给ActivityClientRecord的packageInfo变量,这样就把Activity和
一个程序关联上了。
看下下面的获取代码:

代码片段3



代码片段4
从以上代码可以看到,这个packageInfo是和Application中的packageInfo是同一个对象(同一个LoadedApk对象)。

回到代码片段3中的931行执行:handleLaunchActivity(r, null);

代码片段5

看下1663行,方法代码如下


…..

…….

从上面的代码可以看出和Application的创建过程类似,也是单独放进去一个ContextImpl对象。

Andriod中的Context理解与分析相关链接
(1)http://www.eoeandroid.com/thread-312457-1-1.html
(2)http://www.eoeandroid.com/thread-312978-1-1.html
(3)http://www.eoeandroid.com/thread-312979-1-1.html

[转载]Andriod中的Context理解与分析(1)-Android开发进阶&经验分享-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(898)

[转载]Andriod中的Context理解与分析(1)-Android开发进阶&经验分享-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

大家在应用程序开发的时候会经常遇到Context,也经常使用,那怎么理解Context呢?

在做Web开发的时候也会有一个Context,一般翻译“成上下文”,也就是代表整个程序运行的环境,直到进程结束之后。
那么Android中的Context是不是这样的呢?Android中不是,Android中的Context可以理解成场景,场景是什么什么意思呢?
如果把Android程序的整个运行期间成为一个电影的话,那么一个Activity或者一个Service就可以称之为一个场景,一个电影
可以包括多个场景。
咱们先看下Context相关的继承结构:

从继承关系可以看出,Activity和Service都是基于Context实现的。
Activity不仅基于Context实现,并且还实现了一些重要的其他接口。从设计的角度,继承的才是类的本质,接口仅仅是未来扩充功能。
Activity和Service本质是一个Context,然后扩充了一些功能之后,要么成为Activity,要么成为Service。
而Application也可以认为是为了做一些操作方便,才继承的Context。

也就是说有多少个Activity和Service就有多少个场景,也就是有多少个Context对象(Application也算一个)。

这个Context仅代表一个Activity或者一个Service(Application除外)。

Context的真正实现类是ContextImpl,ContextWraper根据名称可以看出是Context的包装类,在ContextWrap中包装
了ContextImpl,调用ContexWraper的时候也就调用到了ContextImpl的方法。ContextWraper提供了set  ContextImpl
的方法attachBaseContext()。

Activity最终是包含界面的所以他继承了ContextThemeWraper,有Theme这个单词,这个Theme是AndroidMenifest.xml中
的Theme标签对应的Theme。因为Service和Application都不包含界面,就没必须继承ContextThemeWraper了,只需继承
ContextWraper即可。




Application对应的Context

每个应用程序在第一次启动的时候都会产生一个Application,这个Application在整个程序运行期间是唯一的,程序员们可以
根据自己程序的需要重写这个函数,只需继承一下,在需在AndroidMenifest.xml文件的<application>标签上配置下类全名即可,
不配置的话会使用默认的Application。(因为全局是唯一的,可以使用它做一些数据库缓存或者数据传递地方)。

程序第一次启动时,ActivityManagerService会经过ApplicationThread的代理类
远程调用真正的ApplicationThread的bindApplication()方法(这个里把ActivityManagerService当成了Binder客户端,
在ActivityThread中的ApplicationThread对象才是真正的Binder服务端)。

ApplicationThread这个类定义在ActivityThread类文件中。

            代码片段1

这些参数都是从ActivityManagerService通过IPC(Binder方式)传递过来的。如果要在Binder方式中传递对象的话,那么这个类
要实现Parceable接口,看下第一个参数appInfo,通过名字可以知道,是代表应用程序的信息类,这个类按道理肯定实现了
Parceable接口,不错确实实现了这个接口。看下这个类的声明。
、、
           代码片段2

还继承自PackageIntemInfo,PacageItemInfo就是通过AndroidMenifest.xml文件解析出的啊<application>标签中的内容

            代码片段3

从547行开始看,此处创建了一个AppBindData对象data,然后把从ActivityManagerService远程传递过来的参数赋值给data对象,
其中第549行就包括了appInfo赋值给了data对象的appInfo。
咱们看看AppBindData类到底是什么样的,AppBindData是ActivityThread中的内部类。从下面的代码可以看出只是对传过来的参数进行
了简单的封装。

        代码片段4
我们再回到 代码片段1 中的558行其中参数中H.BIND_APPLICATION是继承自Handler的一个类的一个int常量,第二个参数就是刚封装的数据类型data了。
继续代码


    代码片段5

继续代码


        代码片段6

重点就是what参数和obj参数。在1519行获得一个可回收利用的Message对象,然后把传递过来的消息发送到消息队列(1524行),‘
Looper一直在从消息队列里取消息。当取到刚发送的消息后,会回调Handler的handleMessage()方法,继续到H类中
先说明一下,ActivityThread创建时这个H的对象就已经创建好了,这个Handler属于UI线程(主线程)。
    代码片段7
那咱们还是去H这个类的handleMessage()方法吧
其中有个switch结构
H.BIND_APPLICATION对相应的处理如下:


        代码片段8
968行把msg中的obj强制转型成AppBindData,做为handleBindApplication(data)的参数继续执行


        代码片段9
3122行,把data赋值给了mBoundApplication


        代码片段10

3149行,调用getPacageInNocheck()构建一个LoadedApk对象,赋值给data.info。在这个调用中把LoadedApk对象存到了mPackages中。
这个LoadedApk对象,这个对象包含了更多的应用程序的信息。


        代码片段11
第3260行才是真正的使用反射创建一个Application对象,返回值赋值给mInitialApplication。
进入到Loaded.makeApplication()方法,如下

        代码片段12
454行:forceDefaultAppClass这个参数的意思是,是否强制使用系统提供的默认class类,即android.app.Application’
459行:创建了一个ContextImpl实例
461行:创建了一个Application实例,mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext)的具体实现如下:


        代码片段13

942行:继续调用重载的方法


       代码片段14
第958行是设置Application和Context的关联。

调用完整个方法,继续回到代码片段12
463行设置Context和Application的关联。
片段12的代码继续执行到下面,把Application保存到LoadedApk中一份

     代码片段14
这方法执行完成之后回到代码片段11继续执行

        代码片段15

在上面的方法中执行了Application的onCreat()方法

        代码片段16

程序员可以重载Application的onCreate()知道Application创建后的时机,然后做一些相应的操作。

以上就是说明了Application和Context的关系

大致流程如下





Andriod中的Context理解与分析相关链接
(1)http://www.eoeandroid.com/thread-312457-1-1.html
(2)http://www.eoeandroid.com/thread-312978-1-1.html
(3)http://www.eoeandroid.com/thread-312979-1-1.html

[转载]Android ant自动打包脚本:自动替换友盟渠道、版本号、包名 - sink_cup - 博客园

mikel阅读(1536)

[转载]Android ant自动打包脚本:自动替换友盟渠道、版本号、包名 – sink_cup – 博客园.

Android项目开发时,给公司人员安装,频繁升级,版本号总需要改,太麻烦,跟着时间变,自动升级才方便。

Android项目开发新版时,手机上可能要装两个版本,一个是 老的正式版,一个是 新的开发版,想共存的话,要包名不一样,比如chrome是com.android.chrome,而chrome beta是com.chrome.beta,自动改包名才方便。

Android项目正式发布时,要发到国内各个市场上,要统计各个市场的效果,所以打包要打几十次,自动打包才方便。

所以开发了这个脚本,如下:

项目代码:https://github.com/sinkcup/AntDemo

测试APP:http://com-163-sinkcup.qiniudn.com/io.github.sinkcup.ant-cnblogs-1.1.apk

扫描下载

截图:

打包时自动更换友盟渠道

ant auto-release -DUMENG_CHANNEL=googlePlayStore

即会把AndroidManifest.xml中的友盟渠道替换成googlePlayStore,然后打包

ant auto-release -DUMENG_CHANNEL=xiaomiAppStore

即会打出小米应用商店的包

打包时自动更换包名

ant auto-release -Dpackage=com.example.ant.beta

把包名自动改成com.example.ant.beta,然后打包

打包时使用时间作为版本号

ant auto-debug -Dversion=time

把版本号改成时间,然后打包,效果:

versionCode是时间戳,比如1390969254

versionName是日期,比如14.1.29.1220

多个参数任意组合

ant auto-release -DUMENG_CHANNEL=googlePlayStore -Dpackage=com.example.ant.beta -Dversion=time

即打出google play的beta包,使用时间作为版本号

Debug与release签名

ant auto-debug

使用Debug签名(路径~/.android/Debug.keystore),请参考http://developer.android.com/tools/publishing/app-signing.html#debugmode

ant auto-release

使用release签名,请修改ant.properties中的路径、密码等等,参考http://developer.android.com/tools/building/building-cmdline.html#ReleaseMode

如何集成到我的项目里

前提:了解android官方文档,在项目目录中执行ant debug能打包,比如常见的打包步骤:

android update project -p . -s -t "android-19"
ant debug

如果ant debug打包能通过,则可以使用下面的自动打包。

下载custom_rules.xml,放到项目目录(假设为Project1),然后执行:

ant auto-debug -Dversion=time

即可,生成的包在../Project1Tmp/bin/中。

如果想打release包,下载ant.properties,修改其中的密码等配置,然后执行:

ant auto-release -DUMENG_CHANNEL=googlePlayStore -Dpackage=com.example.ant.beta

即可。

PS:友盟支持按渠道升级,比如cnblogs渠道升级完成还是cnblogs,googlePlayStore升级完成还是googlePlayStore。

比如

cnblogs渠道包:http://com-163-sinkcup.qiniudn.com/io.github.sinkcup.ant-cnblogs-1.1.apk

扫描下载cnblogs渠道包

google渠道包:http://com-163-sinkcup.qiniudn.com/io.github.sinkcup.ant-googlePlayStore-1.1.apk

扫描下载google渠道包

运行截图:

[转载]用Qt写软件系列一:QCacheViewer(浏览器缓存查看器) - 24K纯开源 - 博客园

mikel阅读(1284)

[转载]用Qt写软件系列一:QCacheViewer(浏览器缓存查看器) – 24K纯开源 – 博客园.

介绍

Cache技术广泛应用于计算机行业的软硬件领域。该技术既是人们对新技术探讨的结果,也是对当前软硬件计算能力的一种妥协。在浏览器中使用cache 技术,可以大幅度提高web页面的响应速度,降低数据传输延迟,提高web用户的体验。因此,客户端在浏览网页的过程中,会在本地缓存许多文件。随着使用 时间增长,本地缓存的文件日渐增多。对于用户来说,查看本地主机当前的缓存文件数目和种类成为一种迫切的需要。

作为主项目的一部分功能,我们需要完成这样一个浏览器缓存查看器。在网上偶然看到了一款这样的软件:IECacheViewer。 这款软件功能恰到好处,正是我们所需要的。奈何该网站上并未公布其实现方式,因此只好以该软件界面作为模板,自动动手一一实现其功能。寻寻觅觅良久之后, 终于发现了两种实现方式:(1)调用windows系统提供的API。这些API使用简单,只需要循环调用即可获取Cache信息。但缺点是,该方法只能 扫描当前系统中存在的cache文件信息。(2)解析index.dat文件。index.dat文件采用增量记录方法,所有在系统中曾经存在过的 cache文件,在index.dat文件中都有记录。关于index.dat文件是什么,在参考资料中可以得到详尽的答案。我们将在方法二中详细剖析 index.dat的结构。

方法一、调用系统API

1. 相关的API:

 1 HANDLE FindFirstUrlCacheEntry(
 2   __in          LPCTSTR lpszUrlSearchPattern,
 3   __out         LPINTERNET_CACHE_ENTRY_INFO lpFirstCacheEntryInfo,
 4   __in_out      LPDWORD lpcbCacheEntryInfo
 5 ); 
 6 
 7 BOOLAPI FindNextUrlCacheEntry(
 8   __in          HANDLE hEnumHandle,
 9   __out         LPINTERNET_CACHE_ENTRY_INFO lpNextCacheEntryInfo,
10   __in_out      LPDWORD lpcbCacheEntryInfo
11 );
12 
13 BOOLAPI FindCloseUrlCache(
14   __in          HANDLE hEnumHandle
15 );
16 
17 typedef struct _INTERNET_CACHE_ENTRY_INFO  { 
18  DWORD dwStructSize; 
19  LPTSTR lpszSourceUrlName; 
20  LPTSTR lpszLocalFileName;  
21  DWORD CacheEntryType; 
22  DWORD dwUseCount;  
23  DWORD dwHitRate;  
24  DWORD dwSizeLow;  
25  DWORD dwSizeHigh;  
26  FILETIME LastModifiedTime;  
27  FILETIME ExpireTime;  
28  FILETIME LastAccessTime;  
29  FILETIME LastSyncTime;  
30  LPBYTE lpHeaderInfo;  
31  DWORD dwHeaderInfoSize; 
32  LPTSTR lpszFileExtension;  
33  union {    DWORD dwReserved;    DWORD dwExemptDelta;  };
34 } INTERNET_CACHE_ENTRY_INFO, *LPINTERNET_CACHE_ENTRY_INFO;

FindFirstUrlCacheEntry()函数开始枚举Cache信息。其返回一个句柄,该句柄用于所有后续的FindNextUrlCacheEntry()调用。FindCloseUrlCache()函数用户关闭句柄,结束枚举过程。利用上述的三个函数,循环调用并将Cache信息保存在INTERNET_CACHE_ENTRY_INFO结构体中。INTERNET_CACHE_ENTRY_INFO结构体包含了当前Cache文件的详细信息,如文件大小、命中次数、访问时间、修改时间、同步时间等。这样,就可以完成IE Cache信息的提取了。

方法二、 解析index.dat文件

1. 文件结构

如果解析PE文件一样,在解析index.dat文件之前,我们需要知道index.dat文件的组织结构。网上并没有找到index.dat文件的结构说明,只能依着搜到的几个结构体定义来查看index.dat的结构了。大致示意图如下:

一个index.dat文件以small header开始,该small header占0x250个字节,其结构定义如下:

其中最重要的字段是dwHashTableOffset,该字段是DWORD型,在32位机器上占4个字节。dwHashTableOffset保 存了index.dat文件中的第一个hash section的地址。nDirCount和DirArray字段分别表示子目录个数和子目录名称数组。通常对于Cache来说,所有的缓存文件都放在一 个目录中,这两个字段作用不大。而对于Cookie来说,Cookies文件可能分布于多个子目录中。跟在Small header后面的是full header。其具体作用不详,定义如下:

再来看Hash Section部分。每个hash section都有一个头部,占16个字节。其定义如下:

hash头部的dwSig字段占4字节,是由“HASH”这个四个字母的ASCII码填充的。nBlocks字段表明本哈希节占用多少个块,块单位为0x80字节。dwNext字段指出下一个hash 头部的开始地址,以index.dat文件的起始地址为基准。nOrder则是当前哈希节的编号。紧随头部的便是hash itmes了。一个hash item占8字节,前4字节是哈希值,后4字节是Cache记录在index.dat文件中的偏移,也是以index.dat文件的起始地址为基准

2. 分析实例

下面以我的机器上的index.dat文件为例进行实例分析:

 

根据第一个哈希表的偏移地址(0x4000),跳到0x4000处,如下:

可以看到,hash头部第一个字段为:48, 41, 53, 48.为”HASH”四个字母。紧接着的四个字节值为0x20,单位为块,每块大小为128字节。值得注意的是,由于我使用的是小端机(little endian:大端高位在前,小端低位在前),因此需要转换一下。第三个四字节值为0x11000,是下一个hash section的头部地址。第四个四字节值为0,表明当前hash section的编号为0。我们再接着看0x4010位置的值。根据上述的结构定义可知,第一个四字节是哈希值,不用管它。接下来的0x1BA00才是最 重要,它指明了hash条目在文件中的偏移位置。注意相对的偏移基准。我们再跳到0x1BA00位置:

这是一个URL类型。在index.dat文件中,hash条目有多种类型,在参考资料中有说明,这里不再赘述。不过,我们应当重点看看hash条目的定义结构:

按着字段大小一一提取即可。到这里,完成了一次cache信息的提取。我们接着要做的,是查看下一个hash section。因此,再跳到0x11000处:

当前编号为1,下一个hash section 在0x23000处。再跳到0x23000看看:

果然,此时下一个hash section 的地址为0,表明这是最后一个section了。当前编号为2.由此可知,这个index.dat文件中只有3个section。所有的hash条目都可 以依此提取出来。值得注意的是hash section中存在着空洞。如遇到两个字段都为3或者1,表明这是一个空洞。如下图所示,继续查看,仍然有hash条目存在。当遇到两个字节都是 0xDEADBEEF,说明后面不再有hash条目了。

预览效果

参考资料

  1. Windows 中 Cookie、Internet Temp Files、History、Temp Directory 具体路径(2000、Xp、Vista、Win7)
  2. 很好的文章:index.dat的分析(也详细介绍了cookie)
  3. A few words about the cache / history on Internet Explorer 10
  4. Index.Dat Files and Primary I.E. Folders
  5. Understanding Microsoft Internet Explorer Cache
  6. Reading the Internet Explorer Cache
  7. Exploring the URL Cache

代码

View it on github.

[转载]ASP.NET MVC 中实现View与Controller分离 - 脑瓜子 - 博客园

mikel阅读(1210)

[转载]ASP.NET MVC 中实现View与Controller分离 – 脑瓜子 – 博客园.

一、开篇题外话

 

我经常会在博客园逛来逛去,看过很多大牛们的Blog,我很少在这块技术天地活动,之前有发表过几篇日志,好像大部分是和电商有 关,作为一个多年的开发人员,很少在这里分享,之前一直在CSDN上活动,因为我的Blog在那上边的排名1000多名,我想好好维护好CSDN,但是我 发现越来越多的同行们都转战博客园。所以我也跟风来到此块宝地,我来了,你在哪?

 

二、分离的优点

1.松耦合:耦合是指一个系统的组件之间的相关程度。越少的组件相互依赖,那么这个系统的重用性和灵活性就越好。

2.更好的团队分工合作,专门的工程师负责Controller

IC376097

三、背景

在看博客园创始人@dudu博客的时候,发现他就是这样做的,这个是他的项目截图:

2012121411510365我想,我的项目中应该也要这样来实现,下面我们一步一步来分解。

四、实战

 

1、新建一个空的MVC 项目,命名为:NaoGuaZi.MvcExample12。如何新建在此不作一一介绍,

如果不分离的话,我们就开始在该项目下的Controllers文件夹添加Controller,但是我们现在的作法是将Controller作为一个单独的项目,这个项目仅仅用来做View的操作,那究竟怎么实现呢?

具体请猛击下载源码

2、新建一个类库,命名为NaoGuaZi.MvcExample12.Controllers 如下图所示

image

3、在此类库中添加System.Web.dll,System.Web.Abstractions.dll,System.Web.Mvc.dll,System.Web.Routing.dl的引用,如下图所示

image

4、新建一个 GlobalRoutesTable类,用来注册路由,通过该类衔接Controler与View,这个类会在View的Global.asax中Application_Start使用到。

按照国际惯例上代码

public static class GlobalRoutesTable
    {
        public static void RegisterRoutes(RouteCollection routes) {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
            //default   routes
            routes.MapRoute(
                "Default",
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                new string[] {"NaoGuaZi.MvcExample12.Controllers"}
            ); 
        }
    }

 

6、新建类HomeController类,该类继承System.Web.Mvc.Controller

    public class HomeController:Controller {
        public ViewResult Index() {
            return View();
        }
    }

7、将现有项目NaoGuaZi.MvcExample12.Controllers.dll添加到NaoGuaZi.MvcExample12项目中,然后在global.asax中的Application_Start中加入代码:

NaoGuaZi.MvcExample12.Controllers.GlobalRoutesTable.RegisterRoutes(RouteTable.Routes);

8、在NaoGuaZi.MvcExample12项目中的Views下新建Home文件夹,home文件夹下建index.cshtml 视图,然后Ctrl+F5运行项目,我们就可以看到成功运行的结果了。如下图所示:

image 在实践过程中可能出现的错误汇总:

错误1:如下图所示

 

 

image 错误原因:View中已经注册了一个Default的路由

解决办法:将Views中的默认的Default路由名称改成Default1或其他,或者将RegisterRoutes(RouteTable.Routes);注释掉。

五、延伸

 

可能大家会想到,如果在Controllers中建文件夹,这样更有利于层次分明,那该怎么实现呢?

博客园创始人@dudu的解决方案中提到了用Area来解决,然后到最后他采纳了评论中的配置路由的方案,经过我的测试,这中方案测试不通过,所以还是采用Area的方式来实现。我们紧接上面的内容

1、在NaoGuaZi.MvcExample12.Controllers项目中新建文件夹Admin

2、在Admin文件夹下新建AdminAreaRegistration类,该类继承AreaRegistration

3、在类中插入如下代码:

public class AdminAreaRegistration : AreaRegistration {
        public override string AreaName {
            get {
                return "Admin";
            }
        }
        public override void RegisterArea(AreaRegistrationContext context) {
            context.MapRoute(
                "Admin_default",
                "Admin/{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                new string[] {"NaoGuaZi.MvcExample12.Controllers.Admin"}
            );
        }
    }

4、新建HomeController类继承Controller

public ViewResult Index() {
            return View("~/Views/Admin/Home/Index.cshtml");
        }

5、在NaoGuaZi.MvcExample12项目中的Views下新建Admin/Home文件夹,新建名为Index.cshtml视图。然后Ctrl+F5运行,在浏览器中输入http://localhost:端口号/admin/home/index即可成功访问。

image

完整代码下载 VS2012打开,没有涉及到具体业务的实现,只涉及思想。