In my first post, I explained a little bit about how sagas can be leveraged to deal with the problem of nested transactions—”transactions” that span more than a single message.  There were a few community questions related to me redefining the concept of a saga.  That’s definitely not what I’m trying to do.  Per my understanding, a saga sits there and handles multiple messages and exists to coordinate multiple distinct transactions and perform compensating actions relative to the entire “transaction” as a whole.  While by definition a saga may not be responsible for message ordering and de-duplication of messages, as a side-effect of implementation it can handle those things without difficulty.  If anything, the way I’m utilizing  sagas is perhaps somewhat too narrow—a selected subset of the overall meaning and capability of a saga.  Regardless, the main concern herein is how to apply event sourcing as the persistence mechanism for sagas.

One final thought before we look at some code: why should we even bother using event sourcing for sagas?  Why not just persist the state and be done with it?  That’s a great question.  In fact, there isn’t anything wrong with persisting the state and moving forward, per se.  But as we have seen when event sourcing is applied to aggregates, it gives us, as programmers, the ability to re-evaluate our model, adapt it, and even re-implement it in a completely different way.  Furthermore, in the community there have been various examples of the benefits of testing aggregates through watching the events that are persisted after handling a command.  Anyone who has done this can see that testing in this way is much more natural and it avoids the brittle tests that often exist when doing purely state-based testing against aggregates.  This same idea can be applied to sagas.  In essence, applying event sourcing to sagas allows our sagas to be more agile.

Okay…now the code.  How do we leverage event sourcing to implement a saga?  It’s actually not that bad.  Let’s examine at what ISaga might look like:

public interface ISaga
{
Guid Id { get; }
long Version { get; } // for optimistic concurrency

void Transition(object message);

ICollection GetUncommittedEvents();
void ClearUncommittedEvents();

ICollection GetUndispatchedMessages();
void ClearUndispatchedMessages();
}



This should look somewhat similar to the interface of an aggregate root that utilizes event sourcing.  The primary difference is that we now have an additional set of methods related to getting and clearing undispatched messages.



When a message arrives to be processed it is routed into the appropriate message handler whose “Handle” would look something like this:



public void Handle(OrderReceivedEvent message)
{
var sagaId = message.OrderId; // purchase correlation
var saga = repository.GetById(sagaId);
saga.Transition(message);
repository.Save(saga);
}



Granted, this could potentially be inlined into the saga itself, but for our purposes hear, I am choosing to keep the concept of handling a message separate from giving it to the saga.



We’re not attempting to use any kind of unit of work in this example.  We simply get a message, provide it to the saga, and save the saga using a repository.



The Transition method of such a saga is fairly straightforward:



void ISaga.Transition(OrderReceivedEvent message)
{
orderReceived = true;
orderTotal = message.Total;
stateMachine.Fire(Trigger.OrderReceived);

// to avoid duplication, these should be in a base class
version++;
uncommittedEvents.Add(message);
}



Typically the base class would be responsible for receiving event messages from the caller (in this case the bus message handler) and then routing it either dynamically or statically to the specific Transition method capable of working with the specific event message.



Be aware that we’re not using a 100% pure state machine here.  There are two member variables—“orderReceived” and “orderTotal”.  These variables give the saga a little bit of “memory”.  We will want those variables later.  “orderReceived” is used to help us determine if the state machine can transition to a completed state, while “orderTotal” will be used on the resulting command message once we transition to a Completed state.



(Implementation note: Rather than having separate boolean variables to track each message that is received, you can use an enum and concatenate it using bitwise operations, e.g. orderProgress = orderProgress | Progress.OrderReceived).



State Machines, Transitions, and Memory



In multi-message scenarios, especially as the number of messages being handled grows, it becomes increasingly difficult to use a pure state machine to know where things are without having some kind of “memory”.  This is like the “vending machine state machine” problem.  In that problem, every single pathway for every possible permutation of coin must be explicitly modeled up to the price of the item.  It gets nasty fast, especially as the different kinds of coins such as nickels and pennies are accepted and the price of the item increases.



By utilizing a little bit of “memory”, we are able to side-step a large amount of complexity to keep things simple.  This is where the “orderReceived” variable comes into play in the sample code above.  By using it along with other memory variables, we can leverage the best parts of a state machine:



stateMachine.Configure(OrderState.Open)
.PermitIf(Trigger.OrderReceived, OrderState.Completed,
() => orderReceived && paymentReceived);



The above code is an example of a state machine called Stateless, which is still actively developed as compared to SimpleStateMachine which that author has basically abandoned.  The above code says that when we are in the Open state and the OrderReceived trigger occurs, transition to the “Completed” state when the order has been received AND payment has been received.



When we transition to the Completed state is when something observable happens:



stateMachine.Configure(OrderState.Completed) 
.OnEntry(OnCompleted);

....

private void OnCompleted()
{
undispatchedMessages.Add(new DoSomethingInterestingCommand
{
OrderId = orderId,
Total = orderTotal,
...
});
}



In the above code, we have configured the state machine to invoke the OnCompleted event when the state transitions to Completed.  When that occurs, we add a new message to dispatch into our list of undispatched messages.  Later, during the repository “Save” operation, we’ll perform the actual dispatch.



Message Idempotency



In this above example, no matter how many times the OrderReceived message is handled, it will only result in the state transition to Completed once.  For messages that increment/decrement values, such as CashDeposited and the like, we could easily keep track of the identifier for the message and only increment the value if the message hasn’t been handled before.



Persistence



To load the saga from persist storage, we grab the committed events and transition a new instance of the particular type of saga:



public TSaga GetById<TSaga>(Guid sagaId) where TSaga : class, ISaga, new()
{
var saga = new TSaga(); // can be done in different ways

var stream = this.eventStore.Read(sagaId);
foreach (var @event in stream.Events)
saga.Transition(@event);

saga.ClearUncommittedEvents();
saga.ClearUndispatchedMessages();
return saga;
}



To persist a saga, we do the following:



public void Save(ISaga saga)
{
var events = saga.GetUncommittedEvents();
eventStore.Write(new UncommittedEventStream
{
Id = saga.Id,
Type = saga.GetType(),
Events = events,
ExpectedVersion = saga.Version - events.Count
});

foreach (var message in saga.GetUndispatchedMessages())
bus.Send(message); // can be done in different ways

saga.ClearUncommittedEvents();
saga.ClearUndispatchedMessages();
}



In case of an optimistic concurrency exception, our messaging infrastructure will re-deliver the message and we would rebuild the saga, but this time with the committed events from the other, competing process that caused the concurrency exception.  Then, we would re-apply the message that was the victim of the concurrency exception.



What About “Now”?



One quirk related to event sourcing is the concept of “now”.  Because you’re rebuilding the saga from scratch every time, you can’t persist what “now” is.  If you use DateTime.UtcNow just anywhere inside of your saga, it can result in subtle bugs because DateTime.UtcNow changes each time you rebuild the saga from the events.  A rule of thumb is to ensure that each incoming event message always carries with it the concept of time, e.g. when the order was accepted.  Any timeout messages that occur can also carry the time at which they timed out.  Lastly, any messages that are going to be dispatched can get DateTime.UtcNow.



Conclusion



Why use event sourcing for sagas?  Options.  Just like event sourcing for aggregates opens up a world of possibilities, it can do the same thing with sagas.  Even if you don’t buy into the idea of using event sourcing with sagas, do try to understand the importance of sagas as a pattern and where they fit in a messaging-oriented world.



I have applied the above concepts, including ISaga, SagaBase, and SagaRepository, into myCommonDomain project on GitHub.  Perhaps this isn’t quite the best place for the code, but I wanted to get something out for people to see.

posted @ 2011-01-27 00:07 四眼蒙面侠 阅读(77) 评论(0)  编辑

For starters, what is a saga?  A saga is a “long-lived business transaction or process”.  Okay, so what does that mean?  Well, first of all, the “long-lived” part doesn’t have to mean hours, days, or even weeks—it could literally mean something as short as a few seconds.  The amount of time is not the important part.  It’s the fact that the “transaction”, business process, or activity spans more than one message.  Udi has written several times on sagas.  His articles are always worth reading.  The foundational theory behind sagas is to avoid the use of blocking (and locking) transactions across lots of resources.  Locks are one of the primary enemies of scalability.

Late last week I was communicating with Rinat Abdullin on the CQRS Google Group about sagas and explaining how they might be implemented using event sourcing.  I have spoken of this to others in the past as well. In the aforementioned thread, I didn’t go into much detail about the “how”.  Hence this post.

Perhaps we should explain why a saga is even necessary when we have aggregates and domain objects that manage state.  Aggregates are great business objects that wrap a lot of business complexity.  The problem with aggregates is that they only care about their little part of the universe. Sagas, on the other hand, are coordinating objects.  They listen for what’s happening and they tell other objects to take appropriate action.  Picture them as choreographers—let’s try and avoid the words orchestra and orchestration altogether.  In essence, sagas listen for events and instruct other parts of the system to perform tasks based upon the events.  This is juxtaposed to aggregates which are told to do something and then alert the world that they performed some action.  This could be generalized into the following: Sagas listen to events and dispatch commands while aggregates receive commands and publish events.

Sagas manage process.  They contain business behavior, but only in the form of process.  This is a critical point.  Sagas, in their purest form, don’t contain business logic.  During Greg Young’s workshop, he hammered this one pretty hard.  Most programmers think “logic” and aren’t used to thinking “process”.  Let me put it this way.  If you have a saga with “if else” statements, you’ve got logic.  Process is best implemented using a state machine.  The state machine we use to manage process within each saga is called Stateless by Nicholas Blumhardt,the creator of Autofac.

In a message-oriented world, there are two fundamental problems—ordering and duplicates.  These are related to message infrastructure and its corresponding guarantees.  Sagas are able to act as a kind of firewall to the outside.  They encapsulate the mess and help shield the domain from much of the nasty details of reality.

With message ordering, let’s consider how a typical shipping or fulfillment department might utilize sagas to help carry out their responsibilities.  Let’s imagine that fulfillment is not to ship the goods until payment has been received.  As messages can arrive in any order, what would happen if “PaymentRecieved” was the first message to arrive?  In that situation, fulfillment wouldn’t even have a clue what to ship because they haven’t even been made aware of a corresponding order.  With sagas we can easily outline the various state transitions and then dispatch commands only when the appropriate conditions are met—such as the receipt of both the OrderReceived and PaymentReceived events, regardless of the sequence in which they arrive.

Looking at duplicates and idempotency with a state machine-based saga, it’s not hard to see that regardless of the number of times a message is received, it will only cause a state transition once.  Think about it like a DVD player. You hit stop and then stop again.  Not matter how many times you press stop, the state transition only occurs once.  So it is with sagas.  A message can be received multiple times but will only cause the desired state transition once.  This makes duplicate messages naturally idempotent.  Sweet.

The other really great thing about sagas is that they understand the concept of time.  For example, let’s suppose we wanted to notify first-time customers of a discount if they didn’t complete checkout within 48 hours.  The saga could implement a timeout by scheduling a timeout message to be sent back to the saga after 48 hours.  When the timeout message was received 48 hours later, the saga would attempt to perform the state transition related to the timeout.  If the customer did something in the last 48 hours, the timeout message wouldn’t cause a state transition.  But if the person had not yet completed checkout, the saga could dispatch a message to the appropriate component to take corresponding action.  This component would decide the “who” and the “how”.  All the saga did was to tell the component: “There hasn’t been any activity, notify the customer.”  The component would then decide whether or not to notify based upon business logic, e.g. is this a first-time customer, etc.

To Be Continued…

Now that we’ve explained why sagas are important and how state machines can help us implement a saga which deals with the complexity of duplicate messages, out-of-order messages, and timeout messages, in Part II of this article, we’ll look at some of the details of how to use event sourcing to create testable, robust, yet fluid sagas.

posted @ 2011-01-27 00:05 四眼蒙面侠 阅读(54) 评论(0)  编辑

"A SERVICE is an operation offered as an interface that stands alone in the model, without encapsulating state, asENTITIES and VALUE OBJECTS do." [Evans 2003]


The above defines what a Domain Service is. Any behaviour, operation or activity that cannot logically fit into an Object is a good candidate for being exposed as a service. However the important thing to note here is that the Service being exposed should represent a domain concept. This ensures you don't get carried away and create tons of services with very less entities and vo's.


Rules to be followed by Domain Services

A domain service has to abide by only 2 cardinal principles

  1. It has to be stateless
  2. It should have some meaning in domain e.g. AccountTransferService, AdjustOrderService etc

Identifying Domain Services


I carve out a service in any one of the following conditions
  1. The concept behind an entity/vo does not lend itself to the activity being modelled. If by adding the activity concerned the meaning of the entity/vo is diluted, the activity is better off exposed as a service. In other words, if there is no obvious owner expose behaviour as a service.

  2. When the activity being modelled spans across different entities/vo's that are not part of same aggregate, expose a domain service that co-ordinates the activity across the many objects involved.

    For e.g. when adjusting or modifying an existing order, the order, payment and delivery entities have to be updated. I find it more easier and intuitive to model this as a service rather than have all logic in Order.adjust method. To access and modify Delivery/Payment entities, Order entity may have to do a deep object graph traversal. The order entity may not always be qualified to handle this traversal. The OrderAdjustService however, would use a repository to look up all concerned entities and co-ordinate the adjust method among them. This ensures all domain logic of how adjusts happen is still contained within the entities and the service just acts as an orchestrator.

    In fact I like to have an Order.adjust method that the UI/Application layer calls. This Order.adjust method would then call the OrderAdjustService passing in required info. This provides a clean interface and separation of concerns.

  3. If a certain domain logic is applicable across multiple entities and you have to work with a single inheritance model (using java for example), then the logic can be exposed as a service.

    For e.g. multiple entities like Order, Shipment etc need to expose MarketPrice behaviour. The logic to create a price includes looking up real time market prices and currency conversion rates and then calculating the price. A MarketPrice service can encapsulates this logic. The entities should be able to refer the MarketPrice service and delegate all MarketPrice related calls to that service.

    I use this when a ValueObject cannot suffice. In this case there were no fields specific to market price in entities and these were runtime generated and consumed values.

    There is a good description of this technique here. However this is not commonly used.

FAQs on Services

  1. Are'nt Services bad and should'nt we use all objects as per OO ?

    Yes, Services tend to stand orthogonal to Object Oriented Design. Services are not always bad since its far worse to force fit a behaviour into some entity/vo just to be more OO compliant. It messes up the class by distorting its conceptual clarity and makes it harder to understand.

    There is a huge tendency in the modelling world to use excessive number of services. It's easy to stop fitting behaviour to appropriate class and instead stick them into meaningless services. This is when services become bad.


  2. What is an application service and how is it different from domain service ?

    An application service layer defines a set of services that act as boundary to the domain layer. Any interaction with the domain layer passes through these application services. The application services interface with domain and infrastructure layers to get the job done. The domain layer also can talk to infrastructure layer.

    Some excellent point about the distinction between the two can be found here and here.


  3. Can an application service directly talk to a domain service ?

    It depends on your preference on whether you want an explicit entity to own the operation or not.

    However one thing to be clear is that application service layer and domain service layer cannot be combined into one layer. It has been covered with good detail and explanations here and I will not go into them.

    My first take on this was that there is no reason for an application service to talk to domain service. However a colleague of mine had the view that if one service is going to call the other, then application service was not adding much value and it could pick up some of the work that domain service was doing.

    For e.g. our previous OrderAdjustService looks up a bunch of entities and calls appropriate methods on them. We got into an argument that if, this was all it did and had no special logic of its own then it may as well become an application service. However the methods being invoked in all cases were not exposed to application layer. So it was in this context we created a Order.adjust() method that delegated the call to OrderAdjust Service. Having Order.adjust() has an advantage that it makes Order own the adjust operation. If you are not particular about it, you could call OrderAdjustService from application service layer.

Domain services are an important part of Domain Driven Design since they give both flexibility and clarity to the model. As with all good things, use it with moderation !
posted @ 2010-11-02 17:55 四眼蒙面侠 阅读(74) 评论(0)  编辑

Server Application Error

The server has encountered an error while loading an application during the processing of your request. Please refer to the event log for more detail information. Please contact the server administrator for assistance. 

出现 DCOM 遇到错误“登录失败: 未知的用户名或错误密码。 ”并且无法登录到 .\IWAM_APJ006 上以运行服务器


 

解决IIS的Server Application Error办法2007-12-14 00:36 A.M.Server Application Error
The server has encountered an error while loading an application during the processing of your request. Please refer to the event log for more detail information. Please contact the server administrator for assistance.


访问IIS客户端出现如上错信息提示,

在网上查了查解决方案如下:

1。右键我的电脑--管理--本地用户和组,给IUSR_机器名和IWAM_机器名两个用户设置密码,要一样。

2。开始--运行--打cmd,
然后cd D:InetpubAdminscripts(我的系统在D盘),
然后cscript.exe adsutil.vbs set w3svc/wamuserpass 你的密码,
然后cscript.exe adsutil.vbs set w3svc/anonymoususerpass 你的密码

看一下,行了没有?如果还不行,那么
cscript.exe synciwam.vbs -v,
然后iisreset。

据说就可以了,但是到最后一部提示8004e00f的错误,此错误是MSDTC服务不正常造成的,解决方法:

首先进入组件服务,查看组件服务/计算机/我的电脑/COM+应用程序,结果报错“COM+ 无法与 Microsoft 分布式事务协调程序交谈”,无法查看里面的对象。
2、进入事件查看器,发现msdtc服务没有正常启动。
3、删除注册表中的键:
? HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesMSDTC
? HKEY_LOCAL_MACHINESOFTWAREMicrosoftMSDTC
? HKEY_CLASSES_ROOTCID
4、停止MSDTC服务:net stop msdtc
5、卸载MSDTC服务:msdtc -uninstall
6、重新安装MSDTC服务:msdtc -install
7、确认在事件查看器中msdtc服务已经正常启动[这步很关键,如果没有,重新启动下电脑看看]
8、重新设置IIS的IWAM账号密码。[在计算机管理中的用户管理里]
9、同步IIS metabase中IWAM_MYSERVER的密码,在CMD中:c:inetputadminscripts>adsutil set w3svc/wamuserpass "yourpassword"
10、同步COM+应用程序所用的IWAM_MYSERVER密码,在CMD中:c:inetputadminscripts>cscript synciwam.vbs -v

到这部分网上大部分都说可以了,但是我这里虽然没有8004e00f的错误提示了,但是访问页面Server Application Error 错误依旧,最后终于找到了解决方法如下:

解决办法:
[1]:
检查你的DTC服务(全名:Distributed Transaction Coordinator)是否可以正常启动,

如果正常的话请你跳过此步骤;如果出错,无法正常启动,请在开始菜单的运行中 运行:msdtc -resetlog 以创建日志文件。重起机器,检查IIS是否可以正常使用,若不行继续。

[2]:
在CMD下执行以下命令:
cd %windir%\system32\inetsrv

rundll32 wamreg.dll, CreateIISPackage

regsvr32 asptxn.dll

(到这里我就可以用了,不用重启的)

OK,ASP页面一切正常了@!~~~^_^

Server Application Error
The server has encountered an error while loading an application during the processing of your request.Please refer to the event log for more detail information.Please contact the server administrator for assistance.
方法 1:在用户管理器或用户和组中更改密码,使其与 IIS 元数据库密码匹配
1. 在“命令”窗口中,找到 Adsutil.vbs 文件所在的文件夹。使用 Adsutil.vbs 工具从 IIS 元数据库获得 IWAM 和 IUSR 帐户的密码。
2. 若要在 Windows NT 中更改 IUSR 和/或 IWAM 密码,请按照下列步骤操作:

a. 在开始菜单上,指向程序,指向管理工具,然后单击域用户管理器。在“域用户管理器”中,可以更改所有 Windows NT 用户帐户和组的帐户信息。
b. 双击 IUSR_计算机名 和/或 IWAM_计算机名 用户,然后修改密码,使其反映您在步骤 1 中获得的 IIS 元数据库密码。
若要在 Windows 2000 中更改 IUSR 和/或 IWAM 密码,请按照下列步骤操作: a. 在开始菜单上,指向程序,指向管理工具,然后单击计算机管理。
b. 在系统工具节点下,单击以展开“本地用户和组”和“用户”节点。在“用户”节点中,可以更改所有 Windows 2000 用户帐户和组的帐户信息。
c. 右击 IUSR_计算机名 和/或 IWAM_计算机名 帐户,然后单击设置密码。
d. 修改密码,使其反映您在步骤 1 中获得的 IIS 元数据库密码。

3. 浏览返回错误信息的 ASP 页,检查问题是否已解决。

方法 2:更改 IIS 元数据库,使其与 IUSR 和/或 IWAM 密码匹配
1. 若要在 Windows NT 中更改 IUSR 和/或 IWAM 密码,请按照下列步骤操作:

a. 在开始菜单上,指向程序,指向管理工具,然后单击域用户管理器。在“域用户管理器”中,可以更改所有 Windows NT 用户帐户和组的帐户信息。
b. 双击 IUSR_计算机名 和/或 IWAM_计算机名 帐户,然后键入新密码。
若要在 Windows 2000 中更改 IUSR 和/或 IWAM 密码,请按照下列步骤操作: a. 在开始菜单上,指向程序,指向管理工具,然后单击计算机管理。
b. 在系统工具节点下,单击以展开“本地用户和组”和“用户”节点。在“用户”节点中,可以更改所有 Windows 2000 用户帐户和组的帐户信息。
c. 右击 IUSR_计算机名 和或 IWAM_计算机名 帐户,然后单击设置密码。键入新密码。

2. 在“命令”窗口中,找到 Adsutil.vbs 文件所在的文件夹。使用 Adsutil.vbs 实用工具为 IIS 配置数据库中的 IWAM 和 IUSR 帐户设置密码。
3. 浏览返回错误信息的 ASP 页,检查问题是否已解决。
功能 语法
获取 IUSR 帐户密码 cscript.exe adsutil.vbs get w3svc/anonymoususerpass
获取 IWAM 帐户密码 cscript.exe adsutil.vbs get w3svc/wamuserpass
设置 IUSR 帐户密码 cscript.exe adsutil.vbs set w3svc/anonymoususerpass "password"
设置 IWAM 帐户密码 cscript.exe adsutil.vbs set w3svc/wamuserpass "password"

注意:在 Windows NT 4.0 中尝试获取密码时,密码显示为明文;但在 Windows 2000 中,密码显示为星号。若要在 Windows 2000 中也让密码显示为明文,必须修改 Adsutil.vbs,使它显示明码。为此,请按照下列步骤操作: 1. 在“记事本”中,打开 Adsutil.vbs。
2. 在“编辑”菜单上,单击查找,键入 IsSecureProperty = True,然后单击查找下一个。
3. 将“IsSecureProperty = True”更改为“IsSecureProperty = False”。
4. 保存对 Adsutil.vbs 所做的更改,然后关闭“记事本”。

更改 MTS 或组件服务中的密码
Windows 2000/XP/2003
IIS 5.0 提供了 Synciwam.vbs 文件,以便更新在进程外运行的所有 IIS COM+ 应用程序包的启动标识。Synciwam.vbs 脚本位于 <驱动器>\Inetpub\AdminScripts 文件夹中。您可以使用 CScript 或 WScript 运行 Synciwam.vbs。

若要使用 Synciwam.vbs,请在命令提示符处键入下面的命令:
cscript.exe synciwam.vbs -v
为使所有更改生效,您可能需要重新启动 IIS。若要重新启动 IIS,请在开始菜单上,单击运行,键入 iisreset,然后单击确定。

注意:
当COM+损坏时会出现以下现像

在最后的cscript c:\inetpub\adminscripts\synciwam.vbs -v的时候还出现
Error:1AD:ActiveX部件不能创建对象
或通过运行MMC能添加组件服务但是一打开计算机就自动关闭或出错
解决方法就要重新安装COM+
一开始是说,COM+错误

查看事件日志:
出现某种状态,表示此 COM+ 应用程序处于不稳定状态或运行不正常。声明失败: SUCCEEDED(hr)

服务器应用程序 ID: {02D4B3F1-FD88-11D1-960D-00805FC79235}
服务器应用程序实例 ID:
{6615E3FE-D159-48B5-BB65-D6B00778E75F}

这是微软针对2000系统的解决方法:
1.把%WinDir%\System32\Clbcatq.dll删除或改名
2.重启一下
3.进入注册表删除HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\COM3整支(注意备份)
4.运行CMD,打CD %WinDir%回车
5.打rmdir /s Registration回车
6.如果你打过MS04-012补丁请重装一下
7.进入控制面板,点击添加/删除Windows组件
8.重新安装COM+
解决方法如下:

1。右键我的电脑--管理--本地用户和组,给IUSR_机器名和IWAM_机器名两个用户设置密码,要一样。

2。开始--运行--输入cmd,
然后cd c:\Inetpub\AdminScripts
然后cscript.exe adsutil.vbs set w3svc/wamuserpass 你的密码,
然后cscript.exe adsutil.vbs set w3svc/anonymoususerpass 你的密码

看一下,行了没有?如果还不行,那么
cscript.exe synciwam.vbs -v,
然后iisreset

Server Application Error续,8004EOOF错误

发现运行C:\Inetpub\AdminScripts\synciwam.vbs时报8004EOOF错误,晕死,网上搜索了下,发现是

MSDTC的问题: msdtc服务没有正常启动。 找到原因就好办啦^_^

Step1

删除注册表中的键:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSDTC

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC

HKEY_CLASSES_ROOT\CID

Step2

停止 MSDTC服务:net stop msdtc

Step3

卸载MSDTC服务:msdtc -uninstall

Step4

重新安装MSDTC服务:

msdtc -install

然后再按照原来的解决Server Application Error的方法就可以了

如果还不行的话,这时把IIS卸掉,重新安装就可以了啊


 

未能访问 IIS 元数据库

KB: http://support.microsoft.com/?kbid=267904

如果是ASP 2.0就用  aspnet_regiis - ga <WindowsUserAccount>

应该是 aspnet_regiis -ga IWAM_Machinename

未能创建 Mutex  

解决未能创建Mutex的问题 1 如果你还开着VS2005,关掉。2 到ASP.NET的临时目录下面<Windows dir>\Microsoft.Net\Framework\v2.0<extra numbers>\Temporary ASpNET pages3 删除你的项目的那个目录(或者都删除也行)4 重启IIS(如果在命令行下输入 iisreset)5 先打开IE访问你的项目6 然后再打开VS2005

未将对象引用设置到对象的实例 System.Web.Hosting.ISAPIWorkerRequestInProc.GetServerVariable

http://dev.communityserver.com/forums/p/474748/531732.aspx

"aspnet_regiis -i" did the trick

 解决:服务器无法加载应用程序 '/LM/W3SVC'。错误是 '找不到指定的元数据'。

http://blog.csdn.net/wangshangy/archive/2007/03/20/1534639.aspx

解决办法:
                [1]:
                检查你的DTC服务(全名:Distributed Transaction Coordinator)是否可以正常启动,如果正常的话

                请你跳过此步骤;如果出错,无法正常启动,请在开始菜单的运行中 运行:msdtc -resetlog  

                以创建 日志文件。
               
                如果运行这个命令没出错 请跳过下面这行字。

                如果运行这个命令出错请转到本文的下半部分的这个地方开始看。(==== 以下部分是网上重新找的资料 (如果执行上面步骤仍然不行,请继续) ==)

                重起机器,检查IIS是否可以正常使用,若不行继续。

                [2]:
                在CMD下执行以下命令:
                cd %windir%\system32\inetsrv 

                rundll32 wamreg.dll, CreateIISPackage 

                regsvr32 asptxn.dll

                重起机器,我的问题到这步已经可以完美解决!

至此,终于解决IIS报错的问题,,有点乱,但有时间整理问题解决的过程。

 

综合分析上面的错误表现我们可以看出,主要是由于IWAM账号(在我的计算机即是IWAM_MYSERVER账号)的密码错误造成了HTTP 500内部错误。

 

在详细分析HTTP500内部错误产生的原因之前,先对IWAM账号进行一下简要的介绍:IWAM账号是安装IIS5时系统自动建立的一个内置账号,主要用于启动进程之外的应用程序的Internet信息服务。IWAM账号的名字会根据每台计算机NETBIOS名字的不同而有所不同,通用的格式是IWAM_MACHINE,即由“IWAM”前缀、连接线“_”加上计算机的NETBIOS名字组成。我的计算机的NETBIOS名字是MYSERVER,因此我的计算机上IWAM账号的名字就是IWAM_MYSERVER,这一点与IIS匿名账号ISUR_MACHINE的命名方式非常相似。

 

IWAM账号建立后被Active DirectoryIIS metabase数据库和COM+应用程序三方共同使用,账号密码被三方分别保存,并由操作系统负责这三方保存的IWAM密码的同步工作。按常理说,由操作系统负责的工作我们大可放心,不必担心出错,但不知是BUG还是其它什么原因,系统的对IWAM账号的密码同步工作有时会失败,使三方IWAM账号所用密码不统一。当IISCOM+应用程序使用错误IWAM的密码登录系统,启动IIS Out-Of-Process Pooled Applications时,系统会因密码错误而拒绝这一请求,导致IIS Out-Of-Process Pooled Applications启动失败,也就是我们在ID10004错误事件中看到的“不能运行服务器{3D14228D-FBE1-11D0-995D-00C04FD919C1} ”(这里{3D14228D-FBE1-11D0-995D-00C04FD919C1} IIS Out-Of-Process Pooled ApplicationsKEY),不能转入IIS5应用程序,HTTP 500内部错误就这样产生了。

 

 

 

三、解决办法:

 

1、重设IWAM密码

 

打开我的电脑"管理",切换到"本地用户和组",单击"用户"选中"IWAM_computer_name"用户,右击选择"设置密码",在跳出的重设密码对方框中给IWAM_computer_name设置新的密码,这儿我们设置成"rock2006"(没有引号的),确定,等待密码修改成功。

 

2、同步IIS metabaseIWAM_computer_name账号的密码

 

可能因为这项改动太敏感和重要,微软并没有为我们修改IIS metabaseIWAM_computer_name账号密码提供一个显式的用户接口,只随IIS5提供了一个管理脚本adsutil.vbs,这个脚本位于C:\inetpub\AdminScripts子目录下(位置可能会因你安装IIS5时设置的不同而有所变动)

 

adsutil.vbs脚本功能强大,参数非常多且用法复杂,这里只提供使用这个脚本修改IWAM_computer_name账号密码的方法:

 

进入在cmd下进入C:\inetpub\AdminScripts

cd C:\inetpub\AdminScripts

C:\inetpub\AdminScripts>adsutil SET w3svc/WAMUserPass Password "rock2006"

 

修改成功后,系统会有如下提示:

 

WAMUserPass                     : (STRING) "**********"

 

3、同步COM+应用程序所用的IWAM_computer_name的密码

 

同步COM+应用程序所用的IWAM_computer_name的密码,我们使用组件服务MMC管理单元。

 

(1)、打开控制面板,进入管理工具,找到“组件服务”->“计算机”->“我的电脑”->COM+应用程序”->Out-Of-Process Pooled Applications”,右击“Out-Of-Process Pooled Applications->“属性”。

 

(2)、切换到“Out-Of-Process Pooled Applications”属性对话框的“标志”选项卡。“此应用程序在下列账户下运行”选择中“此用户”会被选中,用户名是“IWAM_computer_name”。这些都是缺省的,不必改动。在下面的“密码”和“确认密码”文本框内输入正确的密码“rock2006”,确定退出。

 

(3)、系统如果提示“应用程序被一个以上的外部产品创建。你确定要被这些产品支持吗?”时确定即可。

 

如果我们在IIS中将其它一些Web的“应用程序保护”设置为“高(独立的),那么这个WEB所使用的COM+应用程序的IWAM账号密码也需要同步。重复(1)-(3)步,同步其它相应Out of process applicationIWAM账号密码。

posted @ 2008-08-01 16:51 四眼蒙面侠 阅读(271) 评论(0)  编辑
posted @ 2008-04-15 17:23 四眼蒙面侠 阅读(66) 评论(0)  编辑
posted @ 2008-04-15 16:10 四眼蒙面侠 阅读(45) 评论(0)  编辑

 

       假如你写过很多程序,你可能偶尔会碰到要确定字符或字符窜串否包含在一段文字中,在这篇文章中,我将讨论使用CHARINDEX和PATINDEX函数来搜索文字列和字符串。我将告诉你这两个函数是如何运转的,解释他们的区别。同时提供一些例子,通过这些例子,你可以可以考虑使用这两个函数来解决很多不同的字符搜索的问题。
        CHARINDEX和PATINDEX函数常常用来在一段字符中搜索字符或者字符串。如果被搜索的字符中包含有要搜索的字符,那么这两个函数返回一个非零的整数,这个整数是要搜索的字符在被搜索的字符中的开始位数。PATINDEX函数支持使用通配符来进行搜索,然而CHARINDEX不支持通佩符。接下来,我们逐个分析这两个函数。

如何使用CHARINDEX函数

       CHARINDEX函数返回字符或者字符串在另一个字符串中的起始位置。CHARINDEX函数调用方法如下:

       CHARINDEX ( expression1 , expression2 [ , start_location ] )

       Expression1是要到expression2中寻找的字符中,start_location是CHARINDEX函数开始在expression2中找expression1的位置。

       CHARINDEX函数返回一个整数,返回的整数是要找的字符串在被找的字符串中的位置。假如CHARINDEX没有找到要找的字符串,那么函数整数“0”。让我们看看下面的函数命令执行的结果:

      CHARINDEX('SQL', 'Microsoft SQL Server')

      这个函数命令将返回在“Microsoft SQL Server”中“SQL”的起始位置,在这个例子中,CHARINDEX函数将返回“S”在“Microsoft SQL Server”中的位置11。
接下来,我们看这个CHARINDEX命令:

      CHARINDEX('7.0', 'Microsoft SQL Server 2000')

      在这个例子中,CHARINDEX返回零,因为字符串“7.0” 不能在“Microsoft SQL Server”中被找到。接下来通过两个例子来看看如何使用CHARINDEX函数来解决实际的T-SQL问题。

     第一个例子,假设你要显示Northwind数据库Customer表前5行联系人列的Last Name。这是前5行数据
           ContactName
           ------------------------------ 
           Maria Anders
           Ana Trujillo
           Antonio Moreno
           Thomas Hardy
           Christina Berglund

      你可以看到,CustomName包含客户的First Name和Last Name,它们之间被一个空格隔开。我用CHARINDX函数确定两个名字中间空格的位置。通过这个方法,我们可以分析ContactName列的空格位置,这样我们可以只显示这个列的last name部分。这是显示Northwind的Customer表前5行last name的记录!

               select top 5 substring(ContactName,charindex(' ',ContactName)+1 ,
                      len(ContactName)) as [Last Name] from Northwind.dbo.customers

下面是这个命令输出的结果。
           Last Name
           ------------------------------ 
           Anders
           Trujillo
           Moreno
           Hardy
           Berglund

      CHARINDEX函数找到First Name和Last Name之间的空格,所以SUBSTRING函数可以分开ContactName列,这样就只有Last Name被选出。我在CHARINDEX函数返回的整数上加1,这样Last Name不是从空格开始。

      在第二个例子中,即如说你要计算记录中,某一个字段包含特定字符的所有记录数。CHARINDEX函数可以方便的解决你的问题。计算Northwind.dbo.Customer表中Addresses字段中包含单词Road或者它的缩写Rd的记录数,选择语句类似这样:

       SELECT count(*) from Northwind.dbo.Customers
       WHERE CHARINDEX('Rd',Address) > 0 or CHARINDEX('Road',Address)> 1

如何使用PATINDEX函数

      PATINDEX函数返回字符或者字符串在另一个字符串或者表达式中的起始位置,PATINDEX函数支持搜索字符串中使用通配符,这使PATINDEX函数对于变化的搜索字符串很有价值。PATINDEX函数的命令如下:

      PATINDEX ( '%pattern%' , expression )

      Pattern是你要搜索的字符串,expression是被搜索的字符串。一般情况下expression是一个表中的一个字段,pattern的前后需要用“%”标记,除非你搜索的字符串在被收缩的字符串的最前面或者最后面。

      和CHARINDEX函数一样,PATINDEX函数返回搜索字符串在被搜索字符串中的起始位置。假如有这样一个PATINDEX函数:

      PATINDEX('%BC%','ABCD')

      这个PATINDEX函数返回的结果是2,这和CHARINDEX函数一样。这里的%标记告诉PATINDEX函数去找字符串“BC”,不管被搜索的字符串中在“BC”的前后有多少字符!
      假如你想知道被搜索字符串是否由特定的字符串开始,你可以省去前面的%标记。PATINDED函数就要这样写:

      PATINDEX('AB%','ABCD')

      这个命令执行的结果返回1,表示搜索的字符串“AB”在被搜索的字符串中“ABCD”被找到。

      使用通配符可以编辑比我以上举得简单例子复杂得多的搜索字符串。假如说你要确定一个字符串是否包含字母A和Z,还有任何数字,这个PARINDEX函数命令可能像这样:

      PATINDEX('%[A,Z,0-9]%[A,Z,0-9]%[A,Z,0-9]%','XYZABC123')

      注意在上面这个例子中的搜索字符部分使用了很多的通陪符。察看SQL Server联机丛书可以获得更多关于通佩符的信息。接下来,我们用两个例子来看PATINDEX和SELECT怎么联合起来使用。
 
      假设你想要找出Northwind.dbo.Categories表中Description字段中是包含单词“Bread”或“bread”的所有记录,那么选择语句就可能是这样:

        SELECT Description from Northwind.dbo.Categories
        WHERE patindex('%[b,B]read%',description) > 0

      这里我用通配符来确定大写和小写的“b”。我在Notthwind数据库中执行这个脚本后,得到下面的结果:
           Description
           --------------------------------------------------------
           Desserts, candies, and sweet breads
           Breads, crackers, pasta, and cereal

      这是再用另外一个额外的通配符来查找一些记录的例子。这个例子是如何选出上面的查询结果中,Description字段的第二子字母不是“e”的纪录。

                   select Description from Northwind.dbo.Categories     
                   where patindex('%[b,B]read%',description) > 0  
                   and patindex('_[^e]%',description) = 1        

      通过在条件语句中增加一个使用^通配符的PATINDEX函数,我们可以过滤掉“Dessert, candies, and sweet breads”这条记录。上面的查询结果只有一条记录。
           Description
           --------------------------------------------------------
           Breads, crackers, pasta, and cereal 

总结

      你现在可以发现CHARINDEX和PATINDEX搜索字符串时的区别了吧。PATINDEX函数支持使用通配符,可以用在很多有变化的查找中。而CHARINDEX不可以。根据你自己不同的情况,这两个函数对你在SQL Server中的字符串的搜索、控制、分析很有帮助。

posted @ 2006-11-03 09:13 四眼蒙面侠 阅读(164) 评论(0)  编辑
posted @ 2006-07-05 09:25 四眼蒙面侠 阅读(288) 评论(0)  编辑
posted @ 2006-02-17 18:18 四眼蒙面侠 阅读(12) 评论(0)  编辑
posted @ 2005-11-13 11:39 四眼蒙面侠 阅读(293) 评论(0)  编辑