|
|
Browse by Tags
All Tags » Service Architecture (RSS)
-
Security programming today tends to contain large amount of plumbing code to handle the modeling, management, and evaluation of identities. An identity is the basis of many common security operations, such as authentication, personalization, authorization, and access control. There are a variety of different kinds of identities and ways of implementing security operations on top of those identities. Here are two libraries that help make dealing with identities easier. Zermatt is a claims-based identity system that focuses on simplifying the use of claims in web services. You can download Zermatt from its Connect site. LeastPrivilege.IdentityModel is a library by Dominick Baier that simplifies the existing identity model rather than introduces a new one. You can download LeastPrivilege.IdentityModel from leastprivilege.com. Next time: Trusting IP Addresses Read More...
|
-
Slide decks are available from the Architect Insight Conference 2008 held in the UK at the end of April. These talks are fluffier than ones that I normally point to and since you only have the slides and not the audio, I recommend picking a few based on their titles and trying them out quickly to see if you find something interesting. Here are two that I thought looked interesting. Building an Enterprise Service Bus with BizTalk Server 2006 & WCF Standardising SOA You can access all of the content from the post event resources . Read More...
|
-
Some tips for building support for versioning into the naming of data contracts. First, the primary route for versioning should be through the namespace part of the contract rather than the member name part of the contract. Versioning the contract through member names tends to leak across the service boundary more forcefully. The programming experience of the service often makes a member name directly visible while a namespace is more or less invisible. Second, choose a single consistent scheme for identifying the version. Two popular schemes are the date of the contract and a sequential numbering system of major and minor versions. Both schemes provide the basic element required of a versioning identity, which is an unambiguous total order among the different versions. However, multiple schemes should not be mixed together for a single contract and preferably not for a single system as well. The date scheme, http://company.com/year/month/name, has issues around granularity but can be very evocative since you probably already associate dates in your mind with other events. The issue with granularity is that you have to plan ahead for a maximum update frequency. In the previous example, two updates in the same month would collide with the same name, suggesting that a contract that is updated frequently might include additional levels of refinement, such as the day of the month. However, unnecessarily fine granularity makes the name cumbersome. The numbering scheme, http://company.com/major/minor/name, gives less of a clue about what the version corresponds to but has fewer issues with granularity. Updates can happen as frequently as you want since you can just keep picking new numbers. However, you still have to give some thought to granularity when deciding how many numbering components to include. For example, a single version number may be sufficient if no distinction is needed between major and minor updates. Next time: Finding a Client Channel Read More...
|
-
The WCF Security Guide content that I've mentioned a few times before is now done with early drafts and has been rolled up into a beta release of the full book. There's a ton of content in the real thing on top of what you've been seeing in the drafts. You can download the beta of the full security guide from CodePlex now. If you want to know what I think about the guide, here's the foreword I wrote for them: The computer industry has come to a realization – based on many years of slowly learning from painful experiences – that computer networks are hostile environments. Nevertheless, computer users demand as part of their basic expectations that applications take advantage of the ubiquitous and continuously available connectivity at their disposal to deliver a rich connected experience. It is now your task to design and assemble the loosely coupled service components that you have available in a way that blunts threats and thwarts attacks on the user’s precious assets. Your applications must withstand the hazards of living in a hostile networked environment. To make that possible, you must understand the risks that your applications face and you must be certain that the remedies you put in place properly mitigate the dangers of those risks. As someone who has been through several rounds of security and threat modeling for Windows Communication Foundation, I can say without hesitation that knowledge and experience are your greatest assets for designing secure Web service applications. The trick is to gain as much of that knowledge as possible from the painful experiences of other people rather than painful experiences of your own. J.D. Meier and team have done a fantastic job of assembling and digesting countless practical experiences into a convenient and centralized resource. Practitioners of service-oriented development with WCF will want to use this guide as both a means of learning about the fundamentals of Web service security and a reference for getting specific, step-by-step instructions for dozens of the most common security problems. I enjoy that this guide collects together several different approaches for learning about and implementing security solutions. By combining a variety of formats – scenarios, how-to articles, and guidelines are only a sample of the offered modes – solutions are both reinforced and made more easily discoverable through different entry points. The reason that I’m so excited to see Improving Web Services Security: Scenarios Read More...
|
-
I'm a big fan of using service virtualization to solve a variety of problems with developing and managing web services. The Managed Services Engine is a solution built on top of WCF to supply a repository-based runtime and management tool for service virtualization. I hope to someday put the solutions team out of business by making service virtualization easier to do in the product. For now though, the Managed Services Engine is one of the better web service virtualization systems that I've seen. You can get their new June CTP on CodePlex , which replaces the previous beta release from last October. Read More...
|
-
FaultException supports both an untyped variant, for when you don't have any particularly interesting detail to provide, and a typed variant, for when you do. Don't use a subclass of Exception as the type of a typed FaultException. Here's why. When you use a typed FaultException, you are creating a fault contract between the client and service about data that gets exchanged and a common type system that the two share. By using a CLR exception type, you are unnecessarily forcing that common type system to reflect details of the CLR type system. That type dependency will make it more complicated in the future to move your services and clients to other platforms and possibly even to other versions of the framework. When moving to another version of the framework, you may change the exception profile of your application and start receiving exception types that are more specific or different than the exception types that you received before for a particular error. If you pass those exceptions through to the client, then those platform implementation details are now leaked across the service boundary. Finally, there's no guarantee that the interesting information in a CLR exception will be preserved across the boundary. Most of the interesting contents of exceptions are not serializable. Instead of creating a FaultException with a subclass of Exception, you should define a fault contract that is meaningful for your application or business user. This fault contract can be crafted according to the needs of your service and will remain independent of any particular platform or technology choices that you may need to make later. Next time: Faster Known Types in Orcas Read More...
|
-
One of the things that happens when a new technology framework is introduced with new patterns and best practices is that people wonder what's going to happen with the frameworks that they use today. When WCF was announced a few years ago, users of Remoting were asking this question a lot. The answer then (I have actual quotes from people) was that the introduction of WCF does not mean that Remoting is dead. A lot of scenarios that were formerly done with Remoting can now be done better with WCF, but Remoting does not go away. I still see people asking this question, and the answer has not changed. I would not be surprised to see applications continue to come out with support for Remoting, but I would expect that those applications would represent a smaller percentage of the overall market. There are going to be some times when Remoting is actually the preferred choice. Just like we say with ASMX, if you have an existing application that works today with Remoting, then there's no reason that you have to go out and rewrite it. There should be a preference to use WCF in new applications, but there's no reason to do a conversion unless you actually need to make use of the new features. Remoting also has benefits in some particular scenarios. The fastest standard transport for WCF today is the named pipe transport. Remoting can beat the performance of named pipes if you're communicating between two endpoints within the same process. WCF would be preferable if you want the flexibility to change the scope of the endpoints later or to use a consistent programming model at different scopes, but Remoting is useful if what you care about is performing that scenario as fast as possible. Next time: SVC Files and Services Read More...
|
-
You have talked in the past about how a service has both local settings and settings that are shared through policy. How can I transmit all settings through policy to the client? The two types of settings are clearly distinguishable. Shared settings are required to have agreement between the client and server for the two to interoperate. Examples of shared settings are the protocols and formats being used to transmit messages. Local settings are not required to have agreement between the client and server for the two to interoperate. Examples of local settings are the limits for the time and space allowed to process a message. Local settings can not only be in disagreement between the client and server, but they frequently do not make sense to share between the two. The messages sent between the client and server are rarely symmetric. The processing resources available to the client and server are rarely the same. The security concerns of the client and server are rarely in agreement. You can transmit local settings by creating your own policy assertions that both sides implement. This will involve a lot of hassle, particularly if the service wants to have local setting values that are different than those sent in the policy. Finally, the client will need to absolutely trust the service because you are asking the user to run with settings that were supplied by a third party. Why do you want to do this using policy? It seems that if you have such a level of trust with the client, then you probably already have more direct ways of pushing configuration and executables to the client machine. Next time: Enabling Performance Counters Read More...
|
-
A delegate is a special type that can be bound at execution time to a method invocation. Normally you'd think of method invocations as being synchronous, but delegates can be executed either synchronously in the obvious way or asynchronously by introducing an extra thread of execution. An asynchronous delegate invocation uses the standard BeginInvoke and EndInvoke pattern, with the option to provide a callback for when the work is complete. You would expect that the asynchronous delegate pattern would be an easy way to make asynchronous calls to a web service. You would be wrong. [ServiceContract] public interface IService { [OperationContract] string Echo( string text); } public class Service : IService { public string Echo( string text) { Thread.Sleep(5000); return text; } } public delegate string EchoDelegate( string text); public class BeginInvokeDelegate { static void Callback(IAsyncResult result) { Console.WriteLine( "In callback." ); } static void Main( string [] args) { string uri = "http://localhost:8000/" ; ServiceHost service = new ServiceHost( typeof (Service)); service.AddServiceEndpoint( typeof (IService), new BasicHttpBinding(), uri); service.Open(); ChannelFactory<IService> factory = new ChannelFactory<IService>( new BasicHttpBinding(), new EndpointAddress(uri)); IService proxy = factory.CreateChannel(); EchoDelegate d = new EchoDelegate(proxy.Echo); IAsyncResult result = d.BeginInvoke( "foo" , new AsyncCallback(Callback), null ); Console.WriteLine( "Returned." ); Console.WriteLine(d.EndInvoke(result)); factory.Close(); service.Close(); Console.ReadLine(); } } The code above is using a ChannelFactory against a synchronous version of the Echo interface. The client and service are decoupled so it would have been legal to generate a client proxy that expressed the Echo interface using an asynchronous representation regardless of how Echo is implemented on the server. Instead, the code attempts to make the service call asynchronous by wrapping it in a delegate and using BeginInvoke. If you run this code, then you'll see that the call to BeginInvoke does not complete until after the Echo service call has returned. This defeats the purpose of using the asynchronous pattern. The problem is that BeginInvoke knows about and only works with specific types of proxy objects, which do not include the proxy objects generated by ChannelFactory. The right way to make an asynchronous service call is to generate a proxy that has an asynchronous representation Read More...
|
-
How can I speed up message processing when using MSMQ with WCF? For small gains, it is generally possible to eke out a few percentage points of performance by tuning parameters and settings according to the application domain knowledge you have. For large gains, you are likely going to have to think about larger design issues. In particular, a type of design issue that you should consider in your quest for large gains is to question what features are truly needed to build your application. This article is about a few of those feature decisions that you can make when using MSMQ together with WCF. Since these design decisions require building your application with a restricted set of features, there's no guarantee that these techniques are going to be applicable for you. It really just depends on the queue features you need versus the features you don't. I'm not going to mention features not primarily related to the queue, such as whether to use message security, although obviously the same type of analysis can be applied. Use the NetMsmqBinding instead of the MsmqIntegrationBinding. Of the two bindings, NetMsmq is faster than MsmqIntegration in most cases when similar conditions are applied (for example, both running without security). I have an earlier article describing the differences between the two MSMQ bindings . Disable transactional delivery of messages. The ExactlyOnce option controls whether messages are delivered without being lost or duplicated. Making a delivery guarantee requires that the queue be transactional and issue transactions for transfers. If you need best effort rather than exactly once, turning off transactions noticeably improves performance. Disable durable message storage. If you've already turned off transactions, then you can go significantly farther as well. The Durable option controls whether the queue survives restarting the MSMQ service. If you are using the queue to get asynchronous communication rather than reliable delivery, then leaving messages in a volatile store is another noticeable performance improvement. Pack more messages into the same transaction. Often you can't go as far as turning transactions completely off. A less dramatic step is to use the same transaction for multiple receive operations. The TransactedBatchingBehavior allows you to group messages up to a maximum batch size in a single transaction to amortize creating a transaction across multiple receive calls. Next time: Streaming and ToString Read More...
|
-
How do I push back against clients that are tying up the external connections of my service? The amount of service connection resources used by the client can be thought of as a product of two dimensions. The first dimension is the number of connections that the client has open. The second dimension is the length of time that the client holds the connections open. This is a typical time-space product for measuring utilization. Another way to slice the problem might be network link capacity for space and transfer duration for time. The product that you're going to optimize for is problem dependent, but I'll use number of connections for the example. Each of the dimensions has a quota value that we can use to push back against clients. We push back against space usage by throttling the number of concurrent sessions or instances. This really only makes sense if you have some way of identifying a particular client across multiple sessions because otherwise the client can just knock out other competitors to grab more resources. A typical way of identifying the client is by requiring authentication. You could also do some kind of traffic shaping at the network level although that's best done in front of your service rather than on the same machine. We push back against time usage by limiting the connection lifetime (such as through operation and receive timeouts). The general solution to this problem is to identify the factors that make up the product, pick quotas that protect those factors, and then tune quota values. The balance between the factors is another problem dependent piece. For example, you may have to keep the time quota above a certain value due to the latency of the network connections you're using. However, this is just constraining the range for the corresponding space quota that will let you hit your target value for the product. Next time: Initializing the Context Read More...
|
-
A few days ago I decided to upgrade my home machine from 1 GB of RAM to 2 GB. I've been running Vista at home since last summer and it occasionally gets cranky when it runs out of memory. After the usual problems of fiddling with hardware, everything seemed to be working. Except, Windows Update couldn't find any updates and Outlook couldn't connect to my mailbox. Of course, there wasn't any explanation of what was wrong; they just seemed to have stopped working. I thought that it might be a network problem but I could go to websites without any problem. This lasted for about 10 minutes while I was trying to find a solution, until I went to a website that required SSL. That was when I was surprised to see that the website's certificate was expired, and enlightened when I looked at the details and saw that the certificate was expired because it hadn't been issued yet. The problem wasn't with Windows Update, Outlook, or the website at all, of course. At some point during the hardware upgrade, the onboard clock had been reset to the factory default time of several years ago. This got me thinking about how fragile distributed systems are when clocks are involved . There is an implicit assumption in many systems that network synchronized time will take care of the problem, but clearly synchronization doesn't happen fast enough to cover for certain kinds of failure. These failures make it a bad assumption that the clock time will be reasonably accurate in between the interval of synchronization. Ten years ago I was reading a lot about clockless and unsynchronized systems that only required a steady flow of local time and not a globally coordinated time. This approach seems to have fallen out of favor with ubiquitous Internet connectivity and network time servers. It would be interesting to get an idea of how vulnerable distributed systems are to inadvertent or malicious clock skew on the client and server. I know that many of the common transfer protocols absolutely cannot deal with more than a few seconds of skew and even local behavior like timeouts can be affected by clock changes. Application behavior is also very dependent on accurate timestamps for processing messages. However, I don't think that people pay a lot of attention to this potential weak point in their operations. Read More...
|
-
I have a service contract with a few operations that take large inputs and do a lot of processing. If I configure the service quotas with small values to prevent too many of the expensive operations from happening at once, then the overall throughput is very bad. If I configure the service quotas with large values, then the expensive operations could be called many times and the server will run out of resources. I've left the question off of this one because I'm not actually going to talk about this problem. Instead, the description was a good excuse to talk about the design of service contracts. Long-time programmers will recognize the discussion on chatty versus chunky interface design. Chatty interfaces break operations up into small units of work. It takes a lot of chatty method calls to get something done, but because everything is nicely componentized, it's possible to reassemble the pieces in ways that the original designer didn't think of. Chunky interfaces map large, user-scale operations to a single method call. It only takes a few chunky method calls to get something done, but the operations chosen for the interface are really all you can do. In the non-distributed application world, it often doesn't matter whether your interfaces are chatty or chunky. There were some exceptions. For example, operating system calls have a kernel-mode transition cost so it's beneficial to get a lot of work done with a single call. Every iteration between kernel and user mode results in paying the transition cost. For distributed applications, there is a similar large transition cost called the network. Each trip back to the network introduces a lot of latency relative to the typical computational costs of an operation. COM programming really threw the distinction in your face because it was suddenly a lot harder to predict whether a given method call would incur an expensive transition. You had to program defensively and use lots of chunky interfaces to avoid unpredictable costs at runtime. Typically, calls between application tiers have to be done through chunky interfaces. Calls within an application tier can afford to be chattier. HTTP applications in particular tend to be extremely chunky. Often, requesting a resource will return every single piece of information about that resource and you don't have to make any trips to the server again. This trend has swung back around recently but mostly because the resources are too large to transmit at once (maps of the Read More...
|
-
I've got a few posts on queued and durable messaging coming up over the next few weeks, and we're going to need some vocabulary for those posts that hasn't been used yet while talking about web services. Today's article covers general background around the concept of "poison" messages. Web services without durability or reliability make no guarantee about preserving messages. When failure occurs during message processing, the web service may send back a fault describing that failure, but the original message that caused the fault is destroyed. You can layer some reliability on top of such a messaging system by making buffered copies of messages and using acknowledgments to indicate that processing is complete and the buffered copy can be destroyed. Buffering in memory doesn't really provide any durability because memory is a transient store. There's still no actual guarantee here that messages will be delivered. Now, suppose that the individual messages have a lot of value. The value could be an economic value, but the type of value isn't important for this description. We want to be rigorous now about making delivery guarantees to preserve that value. One way to implement the guarantee is to have a permanent, durable store and some atomic way of linking successful message processing together with deleting the message from the store. Let's call those pieces a queue and a transaction. There is a new problem with the durable service that the non-durable service did not face. In the error-handling case, we have unsuccessful message processing and therefore we do not delete the message from the store. The message will be picked out of the store again in the future to retry processing. If this was a transient processing error, then that behavior is exactly what we want. If this was a permanent processing error, perhaps because the message was malformed, we are going to be locked in a futile cycle of retrieving the message and unsuccessfully processing it. A lot of processing time is wasted making no progress. Poison messages are the idea of these permanently unprocessable messages. We need to take the poison message out of the queue and apply some strategy to it. A typical solution is to move the poison message to some other queue, where it will not be tying up the processing time of our main loop. Next time, we'll look at some of the options for poison message strategies used by MSMQ. Next time: MSMQ and Poison Messages Read More...
|
-
How do I construct callbacks to work over a load balancer without affinity? Let's construct a scenario to demonstrate this question. I have three machines; call them X, Y, and Z. X and Y are together behind a network load balancer. This is a server to server communication scenario, where two servers are attempting to talk over a duplex contract. One of the load-balanced servers, X or Y, is going to first act as the client. Pretend that X is the relevant server in this case. X calls a service with a callback contract to Z. At some point in the future, Z is going to respond on that callback to the load-balanced group. If X passed its real address to Z, then Z has no problem making the callback. If X gives the load-balancer address, then Z will sometimes pick X and sometimes pick Y. The load balancer is not affinitized to a particular machine. The interesting case is where we haven't pinned X as the instance to respond to. What can we do to make sure that the request by X is correlated with the response by Z, regardless of whether that response goes to X or Y? Well, either one of two things needs to happen. Z can stuff all of the necessary context information into the response message so that any server could process the response without having to know about the previous conversation. This is essentially turning a stateful problem into a stateless problem that sends a whole bunch more data. This has turned out to be a pretty interesting solution from the HTTP developer front. X and Y can share a common, durable store of correlation information. This is typically a database, but we don't have to be specific about how X and Y share state between themselves. If you picked something in between going totally stateless and having durable state management, then there would be some interesting implications. There would be situations in which the receiving server would need to invent correlation information out of thin air in order to properly interpret the message. You can fake this some of the time, but sooner or later you'll get caught. Next time: Poison Message Handling Read More...
|
|
|
|