LightSwitch分析--(二) 到底lightswitch在哪里操作了lsml


如何把Sqlserver 里的字段的说明,直接作为Lightswitch的lsml中的字段的DisplayName?


<EntityProperty Name="SortName" PropertyType=":String?">
                <EntityProperty.Attributes>
                    <MaxLength Value="50"/>
                    <DisplayName Value="类型名"/>
                    <Description Value="类型名描述"/>
                </EntityProperty.Attributes>
            </EntityProperty>


我们要解决这个需求,可以有两种方法,一种是写一个解析lsml的工具,在Lightswitch向导,导入数据库完成后,再处理一次,把字段的信息填上。

另一种方面,在crack ls,在导入时,就解决这个问题,

说点题外话,有的代码生成工具,的确会自动把字段的说明,放到生成的代码里,这点还是不错的。


这里,客观来说,前一种方法要好得多。因为,未来如果LS发生改变,我们不需要改变什么,而且,也是一个半自有版权的东西。

但出于好奇,我还是想直接从LS入手。

因为,如果找到LS如何处理lsml的代码,可以省掉许多力气。


可是,问题来了。


事实上,我这个工作,前些天,有一天我研究了大半天,没有取得进展,因为没有找到LS处理lsml 的代码,真是奇怪。


但今天,来我的贴子参观的朋友们有福了,因为我已经明白为什么那天没找到的原因。


可能是MS的LS团队,也认为lsml相关的部分是核心,所以,TMD,他们没有把相关的DLL放到VS中的IDE下的lightswich和VS根目录下的LS中。妈的,真不清楚是为什么。

MS分别把重要的几个库放到:


C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.LightSwitch.Design.CodeGen.Internal\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.LightSwitch.Design.CodeGen.Internal.dll
// Microsoft.LightSwitch.Design.CodeGen.Internal, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a



D:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\


见图:


今天先写到这,如果有朋友,感兴趣,也来尽快参与反向分析工作。

应当是接近了。

我的断点打在:




而且,目前是在关闭LS工程时,触发的。

先到这里,等有进展,再给出来。

// Microsoft.LightSwitch.Designers.DataSourceDesigner.Implementation.Wizard.SelectEntitiesWizardPage
private void LoadTree(object context)
{
	ISelectableEntityViewModel viewModel = context as ISelectableEntityViewModel;
	SelectEntitiesWizardPage.TreeLoaded method = new SelectEntitiesWizardPage.TreeLoaded(this.OnTreeLoaded);
	bool flag = this.LoadTreeSync(viewModel);
	this._uiThreadDispatcher.Invoke(DispatcherPriority.Normal, method, flag);
}


// Microsoft.LightSwitch.Designers.DataSourceDesigner.Implementation.ViewModel.SelectableEntityTypeViewModel
public bool LoadTreeViewModel()
{
	bool result;
	try
	{
		this.SelectEntitiesWaitMessage = this.LoadingEntitiesWaitMessage;
		this.SelectEntitiesWaitMessageVisibility = Visibility.Visible;
		this.SelectEntitiesTreeModel = null;
		this.StorageModel = this.RetrieveStorageModel();
		lock (this.StorageModel)
		{
			this.SortStorageModel(this.StorageModel);
			this.SelectEntitiesTreeModel = this.LoadDataEntities(this.StorageModel);
			List<ITreeViewModel> list = new List<ITreeViewModel>();
			foreach (ITreeViewModel current in this.SelectEntitiesTreeModel)
			{
				if (current.Children.Count == 0)
				{
					list.Add(current);
				}
			}
			foreach (ITreeViewModel current2 in list)
			{
				this.SelectEntitiesTreeModel.Remove(current2);
			}
			if (this.SelectEntitiesTreeModel.Count == 0)
			{
				this.SetSelectEntitiesErrorMessage(new string[]
				{
					this.EmptyTreeErrorMessage
				});
				result = true;
			}
			else
			{
				this.HideSelectEntitiesWaitMessage();
				result = true;
			}
		}
	}
	catch (DataAttachException ex)
	{
		this.SetSelectEntitiesErrorMessage(ex.Errors);
		this.ErrorOccurredInTreeLoad = true;
		result = false;
	}
	return result;
}

// Microsoft.LightSwitch.Designers.DataSourceDesigner.Implementation.ViewModel.DatabaseViewModel
protected override IProviderStorageModel RetrieveStorageModel()
{
	EFDataAttachService eFDataAttachService = this.CreateDataProviderService() as EFDataAttachService;
	if (this.dataConnectionProperties != null)
	{
		return eFDataAttachService.ProvideStorageModel();
	}
	if (this._connectionProperties != null)
	{
		if (this.dataConnectionProperties == null)
		{
			this.dataConnectionProperties = new DataConnectionProperties();
		}
		foreach (IConnectionPropertyDefinition current in this._connectionProperties)
		{
			this.SetConnectionProperty(current, this.dataConnectionProperties);
		}
		string value = (
			from cp in this._connectionProperties
			where cp.Name == "SafeConnectionString"
			select cp).FirstOrDefault<ConnectionProperty>().Value;
		string value2 = (
			from cp in this.ConnectionProperties
			where cp.Name == "ConnectionStringGuid"
			select cp).FirstOrDefault<IConnectionPropertyDefinition>().Value;
		Guid connectionStringGuid = DataAttachUtilities.ConvertStringToGuid(value2);
		this.dataConnectionProperties.EncryptedConnectionString = this.ConnectionManager.GetEncryptedConnectionString(connectionStringGuid, value);
		return eFDataAttachService.ProvideStorageModel();
	}
	return null;
}

// Microsoft.LightSwitch.Designers.DataSourceDesigner.Implementation.Providers.EF.EFDataAttachService
public IProviderStorageModel ProvideStorageModel()
{
	IProviderStorageModel result;
	try
	{
		string value = (
			from cp in this.ConnectionProperties
			where cp.Name == "ProviderInvariantName"
			select cp).FirstOrDefault<ConnectionProperty>().Value;
		string value2 = (
			from cp in this.ConnectionProperties
			where cp.Name == "SafeConnectionString"
			select cp).FirstOrDefault<ConnectionProperty>().Value;
		string value3 = (
			from cp in this.ConnectionProperties
			where cp.Name == "ConnectionStringGuid"
			select cp).FirstOrDefault<ConnectionProperty>().Value;
		Guid connectionStringGuid = DataAttachUtilities.ConvertStringToGuid(value3);
		this._connectionStringGuid = connectionStringGuid;
		ProviderStorageModel providerStorageModel = new ProviderStorageModel();
		IEnumerable<string> enumerable;
		EntityContainer entityContainer = EFHelper.RunEdmGen(this.ConnectionManager.GetConnectionString(connectionStringGuid, value2), value, EFHelper.CreateTablesOnlyFilter(), out enumerable);
		EntityContainer entityContainer2 = EFHelper.RunEdmGen(this.ConnectionManager.GetConnectionString(connectionStringGuid, value2), value, EFHelper.CreateViewsOnlyFilter(), out enumerable);
		providerStorageModel.StorageModelEntities.AddRange(ModelFragmentLoader.GetStorageModelEntities(entityContainer, ProviderStorageModelType.Table));
		providerStorageModel.StorageModelEntities.AddRange(ModelFragmentLoader.GetStorageModelEntities(entityContainer2, ProviderStorageModelType.View));
		this._storageModel = providerStorageModel;
		result = providerStorageModel;
	}
	catch (DataAttachException)
	{
		throw;
	}
	catch (DataException ex)
	{
		throw new DataAttachException(ex.InnerException.Message, ex);
	}
	catch (Exception ex2)
	{
		throw new DataAttachException(ex2.Message, ex2);
	}
	return result;
}



这个最关键的部分,第一次析时,忘记了这段代码,所以后来不得不重来了一次。也好,加深的印象。

// Microsoft.LightSwitch.Designers.DataSourceDesigner.Implementation.Providers.EF.EFHelper
public static EntityContainer RunEdmGen(string connectionString, string providerInvariantName, IEnumerable<EntityStoreSchemaFilterEntry> filters, out IEnumerable<string> warningMessages)
{
	EntityStoreSchemaGenerator entityStoreSchemaGenerator = new EntityStoreSchemaGenerator(providerInvariantName, connectionString, "Tbd");
	IList<EdmSchemaError> source = entityStoreSchemaGenerator.GenerateStoreMetadata(filters);
	IEnumerable<EdmSchemaError> enumerable = 
		from error in source
		where error.Severity == EdmSchemaErrorSeverity.Error
		select error;
	int num = enumerable.Count<EdmSchemaError>();
	if (num != 0)
	{
		string[] array = new string[num];
		int num2 = 0;
		foreach (EdmSchemaError current in enumerable)
		{
			if (current.Severity == EdmSchemaErrorSeverity.Error)
			{
				EFHelper.LoggingService.LogToCategory(EFHelper.LogCategory, LogEventType.Error, null, null, null, null, current.Message);
				array[num2] = current.Message;
				num2++;
			}
		}
		throw new DataAttachException(array);
	}
	warningMessages = 
		from warning in source
		where warning.Severity == EdmSchemaErrorSeverity.Warning
		select warning.Message;
	return entityStoreSchemaGenerator.EntityContainer;
}



// System.Data.Metadata.Edm.EntityType
private object _memberSqlLock = new object();
internal EntityType(string name, string namespaceName, DataSpace dataSpace, IEnumerable<string> keyMemberNames, IEnumerable<EdmMember> members) : base(name, namespaceName, dataSpace)
{
	if (members != null)
	{
		EntityTypeBase.CheckAndAddMembers(members, this);
	}
	if (keyMemberNames != null)
	{
		base.CheckAndAddKeyMembers(keyMemberNames);
	}
}


另外,许多人不明白为什么界面要自动化,老程序员都会给你答案:

因为界面太容易出bug,如果手工写,不论你多仔细,UI的bug,都会占你整个产品的80%以上。

如果,UI人员,只需要把界面风格和框架做好,如果数据出错,就是数据库的schama设计人员的错,当然是一个好的结局。

==============================

昨天回顾了一下代码,想到,最开始看到的那段,才是要找到,那段代码,解释了一个通用问题,也就是如何解析xml文件的,微软的MEF模型,其实不过是xml+schema自动解析xml 的一个实现。

也就是说,lightswitch中,根本没有刻意的解析lsml的代码,真是一个坏消息。

不过,既然是这样,也有好的一面,我们也可以直接利用.net框架,还解析lsml代码,并且转换成我们想要的实体类。

糟糕的是,昨天根到那,我没有太在意,现在还要重新去找。

-------------

首先,我们用找到MEF的EntityType类的构造函数:

System.Data.Metadata.Edm.EntityType



如图所示下断:



我们找到这段最重要的代码:


// Microsoft.LightSwitch.Designers.DataSourceDesigner.Implementation.Providers.EF.EFHelper
public static EntityContainer RunEdmGen(string connectionString, string providerInvariantName, IEnumerable<EntityStoreSchemaFilterEntry> filters, out IEnumerable<string> warningMessages)
{
    EntityStoreSchemaGenerator entityStoreSchemaGenerator = new EntityStoreSchemaGenerator(providerInvariantName, connectionString, "Tbd");
    IList<EdmSchemaError> source = entityStoreSchemaGenerator.GenerateStoreMetadata(filters);
    IEnumerable<EdmSchemaError> enumerable = 
        from error in source
        where error.Severity == EdmSchemaErrorSeverity.Error
        select error;
    int num = enumerable.Count<EdmSchemaError>();
    if (num != 0)
    {
        string[] array = new string[num];
        int num2 = 0;
        foreach (EdmSchemaError current in enumerable)
        {
            if (current.Severity == EdmSchemaErrorSeverity.Error)
            {
                EFHelper.LoggingService.LogToCategory(EFHelper.LogCategory, LogEventType.Error, nullnullnullnull, current.Message);
                array[num2] = current.Message;
                num2++;
            }
        }
        throw new DataAttachException(array);
    }
    warningMessages = 
        from warning in source
        where warning.Severity == EdmSchemaErrorSeverity.Warning
        select warning.Message;
    return entityStoreSchemaGenerator.EntityContainer;
}


好了,本文告一段落,目的已达成。

我们找到了解析lsml最关键的代码。

对于xml 文件解析来说,最关键的就是找到Schema部分,了解过编译器过是学过记算机语言学的人,都理解是怎么回事。

计算机,在解析xml时,好象很神奇,它事先不清楚xml的内容,为什么能“理解”它呢?其它与编译原理是同一套理论,没有任何区别。

现在我们找到了,MEF的底层,如何操作schema的部分所在位置,也找到了调用的代码,后面可以根据自己的想法来尝试了。


在结束前,这里提供与本文相关的ApplicationDefinition.lsml

最重要的是这段:

<ModelFragment xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<EntityType Name="GiftAddRecord">

。。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值