Repository: Azure-Samples/service-fabric-dotnet-web-reference-app Branch: master Commit: c6ebbb208e1d Files: 146 Total size: 414.5 KB Directory structure: gitextract_lulu55kd/ ├── .gitignore ├── CONTRIBUTING.md ├── Docs/ │ └── architecture.md ├── LICENSE ├── README.md └── ReferenceApp/ ├── Common/ │ ├── ActorMessageId.cs │ ├── Common.csproj │ ├── HashUtil.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── ServiceUriBuilder.cs │ └── packages.config ├── CustomerOrder.Actor/ │ ├── ActorEventSource.cs │ ├── App.config │ ├── CustomerOrder.Actor.csproj │ ├── CustomerOrderActor.cs │ ├── CustomerOrderReminderNames.cs │ ├── PackageRoot/ │ │ ├── Config/ │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ └── packages.config ├── CustomerOrder.Domain/ │ ├── CustomerOrder.Domain.csproj │ ├── CustomerOrderItem.cs │ ├── CustomerOrderStatus.cs │ ├── ICustomerOrderActor.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── app.config │ └── packages.config ├── CustomerOrder.UnitTests/ │ ├── CustomerOrder.UnitTests.csproj │ ├── CustomerOrderActorTests.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── app.config │ └── packages.config ├── Inventory.Domain/ │ ├── IInventoryService.cs │ ├── Inventory.Domain.csproj │ ├── InventoryItem.cs │ ├── InventoryItemId.cs │ ├── InventoryItemView.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ └── packages.config ├── Inventory.Service/ │ ├── App.config │ ├── AzureBackupStore.cs │ ├── IBackupStore.cs │ ├── Inventory.Service.csproj │ ├── InventoryService.cs │ ├── LocalBackupStore.cs │ ├── PackageRoot/ │ │ ├── Config/ │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── ServiceEventSource.cs │ ├── StatefulServiceParameters.cs │ └── packages.config ├── Inventory.UnitTests/ │ ├── Inventory.UnitTests.csproj │ ├── InventoryServiceTests.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── app.config │ └── packages.config ├── Mocks/ │ ├── MockActorStateManager.cs │ ├── MockAsyncEnumerable.cs │ ├── MockCodePackageActivationContext.cs │ ├── MockInventoryService.cs │ ├── MockReliableDictionary.cs │ ├── MockReliableQueue.cs │ ├── MockReliableStateManager.cs │ ├── MockServiceProxy.cs │ ├── MockServiceProxyFactory.cs │ ├── MockTransaction.cs │ ├── Mocks.csproj │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── app.config │ └── packages.config ├── Nuget.Config ├── RestockRequest.Actor/ │ ├── ActorEventSource.cs │ ├── App.config │ ├── PackageRoot/ │ │ ├── Config/ │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── RestockRequest.Actor.csproj │ ├── RestockRequestActor.cs │ ├── RestockRequestActorState.cs │ ├── RestockRequestReminderNames.cs │ ├── ServiceHost.cs │ └── packages.config ├── RestockRequest.Domain/ │ ├── IRestockRequestActor.cs │ ├── IRestockRequestEvents.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── RestockRequest.Domain.csproj │ ├── RestockRequest.cs │ ├── RestockRequestStatus.cs │ ├── app.config │ └── packages.config ├── RestockRequestManager.Domain/ │ ├── IRestockRequestManager.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── RestockRequestManager.Domain.csproj │ ├── app.config │ └── packages.config ├── RestockRequestManager.Service/ │ ├── App.config │ ├── PackageRoot/ │ │ ├── Config/ │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── RestockRequestManager.Service.csproj │ ├── RestockRequestManagerService.cs │ ├── ServiceEventSource.cs │ └── packages.config ├── Web.Service/ │ ├── .bowerrc │ ├── App.config │ ├── Controllers/ │ │ ├── HomeController.cs │ │ ├── InventoryController.cs │ │ ├── OrdersController.cs │ │ └── StoreController.cs │ ├── PackageRoot/ │ │ ├── Config/ │ │ │ └── Settings.xml │ │ └── ServiceManifest.xml │ ├── Program.cs │ ├── Properties/ │ │ └── launchSettings.json │ ├── ServiceEventSource.cs │ ├── Startup.cs │ ├── Views/ │ │ ├── Home/ │ │ │ ├── Admin.cshtml │ │ │ ├── Index.cshtml │ │ │ └── OrderConfirmation.cshtml │ │ ├── Shared/ │ │ │ ├── Error.cshtml │ │ │ ├── _Layout.cshtml │ │ │ └── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml │ ├── Web.Service.csproj │ ├── WebService.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── bower.json │ ├── bundleconfig.json │ └── wwwroot/ │ ├── css/ │ │ └── site.css │ └── js/ │ └── angular-index.js ├── WebReferenceApp.sln └── WebReferenceApplication/ ├── ApplicationPackageRoot/ │ └── ApplicationManifest.xml ├── ApplicationParameters/ │ ├── Cloud.xml │ ├── Local.1Node.xml │ └── Local.5Node.xml ├── PublishProfiles/ │ ├── Cloud.xml │ ├── Local.1Node.xml │ └── Local.5Node.xml ├── Scripts/ │ └── Deploy-FabricApplication.ps1 ├── WebReferenceApplication.sfproj ├── app.config └── packages.config ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ [Bb]ackup*/ [Oo]bj/ [Bb]in/ pkg/ objd/ TestResults/ .nuget/ *.sln.ide/ _ReSharper.*/ packages/ .vs/ *.user *.suo *.cache *.docstates _ReSharper.* nuget.exe .settings *.sln.ide ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Azure samples Thank you for your interest in contributing to Azure samples! ## Ways to contribute You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways: - Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/service-fabric-dotnet-web-reference-app/) whether it was helpful or not. - Submit issues through [issue tracker](https://github.com/Azure-Samples/service-fabric-dotnet-web-reference-app/issues) on GitHub. We are actively monitoring the issues and improving our samples. - If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request. ================================================ FILE: Docs/architecture.md ================================================ # Application architecture The application is composed of individual services to perform the major functions of the application: - Web Service - A stateless front-end service that hosts the web UI and HTTP API for interacting with the store. - Customer Order Actor - An actor-based service that handles customer orders. A stateful actor is activated for each new order that's placed. The actor represents the lifetime of the customer order, from placement to fulfillment. - Inventory Service - A stateful service that maintains the store's inventory. This service is partitioned, where each partition of the service holds a subset of the store's entire inventory. With a large number of partitions, this service can scale out to meet data capacity and inventory request throughput. - RestockRequest Actor - A stateful actor that manages the lifetime of a restock request from the inventory service. Each time the inventory runs low on stock for an item, makes a request to refill the inventory. The restock request actor itself would send a request to a supplier for more items, however this is simply simulated within the actor. - RestockRequest Manager - This is a stateful service that manages requests from the inventory service for item restocking. It logs restock requests made by the Inventory Service and activates a RestockRequest Actor to fulfill the requst. It then receives notifications from the actors when a restock request has been fulfilled. These notifications are placed in a ReliableQueue as they come in. The notifications are periodically dequeued and sent back to the Inventory Service. # Data flow When a user makes a purchase, data flows the through the system as follows: ![Data flow](./media/dataflow.png) 1. Client sends HTTP POST to /api/orders with order in JSON payload: [{"ItemId":"1d6abc91-ebe7-41ff-b868-4086501903fc","Quantity":1},{"ItemId":"a833f7d0-2f76-4c9f-9353-8c728252da4a","Quantity":2}] Response from service is a tracking ID: 68bf3f53-dc74-4ef9-8f60-89d68508247b 2. Web Service creates a new Actor (by specifying a new ActorId) to track the order by calling SubmitOrderAsync() on the Customer Order Actor service. 3. Customer Order Actor saves the order in its state, registers a reminder for itself to complete the order, and returns to the caller. Order processing has a number of steps and may need to retry in case of failure, thus the reminder serves as a queued work item within the Actor in order to prioritize saving the order reliably and returning to the caller as quickly as possible. 4. Customer Order Actor processes the order by requesting stock for the order to be removed from the Inventory Service. If there is not enough stock available to fulfill the order, the actor adds the back ordered items to its list of backordered state and registers another reminder on itself to try fulfilling the order again later. If this process completes successfully (either by completing the order or by tracking backorder items), the reminder for this method is removed, which has the effect of removing the queue work item. If at any point the method throws or the service crashes, the reminder will remain and will be executed again automatically to retry fulfilling the order. NOTE: the retry mechanism is not fully implemented yet. 5. Inventory Service checks to see if available stock is below the restock threshold after removing stock as requested by a CustomerOrder Actor. If the stock for a certain item is below the restock threshold and it's not already being reordered, it calls AddRestockRequestAsync on the Restock Request Manager. 6. When the Restock Request Manager receives a restock request, it creates a new Actor to track the request and adds the Actor to its own Reliable Dictionary so that it may query the restock request Actors later. Upon adding the Actor, it subscribes to event notifications from the Actor. This will be used later to notify the Restock Request Manager when the restock request is complete. 7. The Restock Request Actor registers a reminder on itself to go through the restock processing pipeline. This pipeline is normally where restocking logic would live, but currently it is simply faked by progressing through each step of restocking every time the reminder fires. When it reaches the last step in the pipeline, it signals the completed event (for which the Restock Request Manager is listening), and unregisters the reminder when that completes. 8. When the Restock Request Actor completes the restock request, it signals the complete event which sends the completed RestockRequest back to the Restock Request Manager. The Manager queues the completed Restock Request in a Reliable Queue for later processing and unsubscribes from receiving events from the Actor, which is now complete and will eventually be garbage-collected. 9. Restock Request Manager's RunAsync method periodically drains the queue of Restock Requests and sends those Restock Requests to the Inventory Service for restocking. ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Microsoft Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ --- languages: - csharp products: - azure - azure-service-fabric page_type: sample description: "The web reference application shows how to build an end-to-end Service Fabric application with multiple types of services." --- # Service Fabric Web Reference Application The web reference application shows how to build an end-to-end Service Fabric application with multiple types of services, combining Reliable Services and Reliable Actors to construct a complete solution. ## Scenario The context of this sample is a web-based store with a customer order and inventory management back-end. Logical parts of the management back-end are represented by individual services, allowing loose coupling of functionality and independently-upgradeable components: - Customer Order Service - Inventory Service - Restocking Service - Web front-end Service The customer order and inventory management system tracks user orders, removes items from the inventory to fulfill orders, and requests restocking of inventory items when an item's stock goes below a certain threshold. If a user requests items that are out of stock, the order is placed on back-order until the inventory is replenished, at which point the order is completed. Using Service Fabric's stateful services, each of these services can maintain its own data, rather than relying a shared monolithic data base. This allows each service to scale independently using Service Fabric's stateful partitioning to meet its unique requirements for data capacity and throughput. ## Running this sample The majority of this application is self-contained. The only external dependency is to Azure storage for [backup & restore](https://azure.microsoft.com/en-us/documentation/articles/service-fabric-reliable-services-backup-restore/) purposes. There are no other dependencies on external services or databases to manage related to request processing or data persistence. This makes running the complete application pretty easy: 1. Open the .sln solution file in Visual Studio 2015. 2. Edit the Inventory.Service\PackageRoot\Config\Settings.xml file to contain the connection details for your Azure storage account. 2. Press F5 to run. This deploys the entire web store application on your local machine. There are two web endpoints to begin interacting with the application: 1. **http://localhost:8505/fabrikam/admin.html** - a very basic admin portal where you can add items into the inventory. When you first launch the application, the inventory is empty. 2. **http://localhost:8505/fabrikam/** - a basic store front-end. This shows the current inventory and your shopping cart where you can add and purchase items to see the flow of data through the system. ## Deploy this sample to Azure The application can be deployed to Azure by right-clicking the application project in Visual Studio and selecting "Publish". ![Publish dialog](./Docs/media/publish.png) In the publish dialog box, select the Cloud profile and a connection endpoint. Selecting a connection endpoint from this dialog requires an Azure subscription. If you want to publish to a known cluster without an Azure subscription, you can simply edit the Cloud publish profile XML under PublishProfiles in the application project and specify a cluster connection endpoint there: ``` XML ``` ## Unit Tests This application also contains unit tests to show the recommended pattern to create tests against a Service Fabric application. Below are the steps to run or debug a test (using Visual studio 2015 on a 64 bit windows): - Open the WebReferenceApp solution in Visual studio 2015 - Select menus "Test" / "Test Setting" / "Default processor architecture" -> x64 - Rebuild the solution - Select menus "Test" / "Windows" / "Test Explorer" you should see now the text explorer window with the list of available tests - Choose one or more tests (for example "TestAddStock" under InventoryServiceTests) - Right click the test of your choice and select run the test, you will see after a while a green check mark of test passed - You can try also to debug the test to understand better its logic ## Next steps - [Learn about the application architecture and data flow.](https://github.com/Azure-Samples/service-fabric-dotnet-web-reference-app/blob/master/Docs/architecture.md "Learn about the application architecture and data flow.") ## MSFT OSS Code Of Conduct Notice This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. ================================================ FILE: ReferenceApp/Common/ActorMessageId.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Common { using System; using System.Runtime.Serialization; using Microsoft.ServiceFabric.Actors; [DataContract] public class CustomerOrderActorMessageId : IFormattable, IComparable, IComparable, IEquatable { public CustomerOrderActorMessageId(ActorId sendingActorId, long messageId) { this.sendingActorId = sendingActorId; this.messageId = messageId; } [DataMember] public ActorId sendingActorId { get; private set; } [DataMember] public long messageId { get; private set; } int IComparable.CompareTo(object obj) { return this.CompareTo((CustomerOrderActorMessageId) obj); } public int CompareTo(CustomerOrderActorMessageId other) { if (this.sendingActorId.ToString().CompareTo(other.sendingActorId.ToString()) > 1) { return 1; } else if (this.sendingActorId.ToString().CompareTo(other.sendingActorId.ToString()) < 1) { return -1; } else if (this.messageId > other.messageId) { return 1; } else if (this.messageId < other.messageId) { return -1; } return 0; } public bool Equals(CustomerOrderActorMessageId other) { return (this.sendingActorId.Equals(other.sendingActorId) && this.messageId == other.messageId); } public string ToString(string format, IFormatProvider formatProvider) { return string.Format("{0}|{1}", this.sendingActorId.ToString(), this.messageId); } public static CustomerOrderActorMessageId GetRandom() { ActorId id = new ActorId(Guid.NewGuid()); Random r = new Random(); return new CustomerOrderActorMessageId(id, r.Next()); } public static bool operator ==(CustomerOrderActorMessageId item1, CustomerOrderActorMessageId item2) { return item1.Equals(item2); } public static bool operator !=(CustomerOrderActorMessageId item1, CustomerOrderActorMessageId item2) { return !item1.Equals(item2); } public static bool operator >(CustomerOrderActorMessageId item1, CustomerOrderActorMessageId item2) { int result = item1.CompareTo(item2); return (result == 0 | result == -1); } public static bool operator <(CustomerOrderActorMessageId item1, CustomerOrderActorMessageId item2) { int result = item1.CompareTo(item2); return (result == 0 | result == 1); } public override bool Equals(object obj) { return (this.CompareTo(obj as CustomerOrderActorMessageId) == 0); } public override int GetHashCode() { return this.ToString().GetHashCode(); } } } ================================================ FILE: ReferenceApp/Common/Common.csproj ================================================  Debug x64 {9EC0063F-489E-43FE-94B5-BF5F89977CD3} Library Properties Common Common v4.5.2 512 true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/Common/HashUtil.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Common { using System; using System.Security.Cryptography; using System.Text; public class HashUtil { public static long getLongHashCode(string stringInput) { byte[] byteContents = Encoding.Unicode.GetBytes(stringInput); MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider(); byte[] hashText = hash.ComputeHash(byteContents); return BitConverter.ToInt64(hashText, 0) ^ BitConverter.ToInt64(hashText, 7); } public static int getIntHashCode(string stringInput) { return (int) getLongHashCode(stringInput); } } } ================================================ FILE: ReferenceApp/Common/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Common")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Common")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("9ec0063f-489e-43fe-94b5-bf5f89977cd3")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/Common/ServiceUriBuilder.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Common { using System; using System.Fabric; public class ServiceUriBuilder { public ServiceUriBuilder(string serviceInstance) { this.ActivationContext = FabricRuntime.GetActivationContext(); this.ServiceInstance = serviceInstance; } public ServiceUriBuilder(ICodePackageActivationContext context, string serviceInstance) { this.ActivationContext = context; this.ServiceInstance = serviceInstance; } public ServiceUriBuilder(ICodePackageActivationContext context, string applicationInstance, string serviceInstance) { this.ActivationContext = context; this.ApplicationInstance = applicationInstance; this.ServiceInstance = serviceInstance; } /// /// The name of the application instance that contains he service. /// public string ApplicationInstance { get; set; } /// /// The name of the service instance. /// public string ServiceInstance { get; set; } /// /// The local activation context /// public ICodePackageActivationContext ActivationContext { get; set; } public Uri ToUri() { string applicationInstance = this.ApplicationInstance; if (String.IsNullOrEmpty(applicationInstance)) { // the ApplicationName property here automatically prepends "fabric:/" for us applicationInstance = this.ActivationContext.ApplicationName.Replace("fabric:/", String.Empty); } return new Uri("fabric:/" + applicationInstance + "/" + this.ServiceInstance); } } } ================================================ FILE: ReferenceApp/Common/packages.config ================================================  ================================================ FILE: ReferenceApp/CustomerOrder.Actor/ActorEventSource.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.Actor { using System; using System.Diagnostics.Tracing; using System.Threading.Tasks; using Microsoft.ServiceFabric.Actors.Runtime; [EventSource(Name = "MyCompany-Web_UIApplication-CustomerOrder")] internal sealed class ActorEventSource : EventSource { private const int MessageEventId = 1; // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. private const int ActorMessageEventId = 2; private const int ActorHostInitializationFailedEventId = 3; public static readonly ActorEventSource Current = new ActorEventSource(); static ActorEventSource() { // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. // This problem will be fixed in .NET Framework 4.6.2. Task.Run(() => { }).Wait(); } // Instance constructor is private to enforce singleton semantics private ActorEventSource() : base() { } // Define an instance method for each event you want to record and apply an [Event] attribute to it. // The method name is the name of the event. // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). // Put [NonEvent] attribute on all methods that do not define an event. // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx [NonEvent] public void Message(string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); this.Message(finalMessage); } } [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] public void Message(string message) { if (this.IsEnabled()) { this.WriteEvent(MessageEventId, message); } } [NonEvent] public void ActorMessage(Actor actor, string message, params object[] args) { if (this.IsEnabled() && actor.Id != null && actor.ActorService != null && actor.ActorService.Context != null && actor.ActorService.Context.CodePackageActivationContext != null) { string finalMessage = string.Format(message, args); this.ActorMessage( actor.GetType().ToString(), actor.Id.ToString(), actor.ActorService.Context.CodePackageActivationContext.ApplicationTypeName, actor.ActorService.Context.CodePackageActivationContext.ApplicationName, actor.ActorService.Context.ServiceTypeName, actor.ActorService.Context.ServiceName.ToString(), actor.ActorService.Context.PartitionId, actor.ActorService.Context.ReplicaId, actor.ActorService.Context.NodeContext.NodeName, finalMessage); } } [Event(ActorHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Actor host initialization failed", Keywords = Keywords.HostInitialization)] public void ActorHostInitializationFailed(string exception) { this.WriteEvent(ActorHostInitializationFailedEventId, exception); } [Event(ActorMessageEventId, Level = EventLevel.Informational, Message = "{9}")] private void ActorMessage( string actorType, string actorId, string applicationTypeName, string applicationName, string serviceTypeName, string serviceName, Guid partitionId, long replicaOrInstanceId, string nodeName, string message) { this.WriteEvent( ActorMessageEventId, actorType, actorId, applicationTypeName, applicationName, serviceTypeName, serviceName, partitionId, replicaOrInstanceId, nodeName, message); } // Event keywords can be used to categorize events. // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. public static class Keywords { public const EventKeywords HostInitialization = (EventKeywords) 0x1L; } } } ================================================ FILE: ReferenceApp/CustomerOrder.Actor/App.config ================================================  ================================================ FILE: ReferenceApp/CustomerOrder.Actor/CustomerOrder.Actor.csproj ================================================  Debug x64 {5F0C7805-C91D-47E9-AEDE-946CADEA1C8F} Exe Properties CustomerOrder.Actor CustomerOrder.Actor v4.5.2 512 true True true PackageRoot $(MSBuildProjectName) x64 true full false bin\Debug\ DEBUG;TRACE prompt 4 x64 pdbonly true bin\Release\ TRACE prompt 4 ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True Designer {1E7E813F-43D3-4D0B-8546-5E1023873F28} CustomerOrder.Domain {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain {00E00484-BD00-40CD-B2CC-1CFA8E893972} Mocks This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/CustomerOrder.Actor/CustomerOrderActor.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.Actor { using Common; using CustomerOrder.Domain; using Inventory.Domain; using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Actors.Runtime; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Services.Remoting.Client; using Mocks; using System; using System.Collections.Generic; using System.Fabric; using System.Linq; using System.Threading; using System.Threading.Tasks; internal class CustomerOrderActor : Actor, ICustomerOrderActor, IRemindable { private const string InventoryServiceName = "InventoryService"; private const string OrderItemListPropertyName = "OrderList"; private const string OrderStatusPropertyName = "CustomerOrderStatus"; private const string RequestIdPropertyName = "RequestId"; private IServiceProxyFactory ServiceProxyFactory; private ServiceUriBuilder builder; private CancellationTokenSource tokenSource = null; public CustomerOrderActor(ActorService actorService, ActorId actorId) : base (actorService, actorId) { } /// /// This method accepts a list of CustomerOrderItems, representing a customer order, and sets the actor's state /// to reflect the status and contents of the order. Then, the order is fulfilled with a private FulfillOrder call /// that abstracts away the entire backorder process from the user. /// /// /// public async Task SubmitOrderAsync(IEnumerable orderList) { try { await this.StateManager.SetStateAsync>(OrderItemListPropertyName, new List(orderList)); await this.StateManager.SetStateAsync(OrderStatusPropertyName, CustomerOrderStatus.Submitted); await this.RegisterReminderAsync( CustomerOrderReminderNames.FulfillOrderReminder, null, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)); } catch (Exception e) { ActorEventSource.Current.Message(e.ToString()); } ActorEventSource.Current.Message("Order submitted with {0} items", orderList.Count()); return; } /// /// Returns the status of the Customer Order. /// /// public async Task GetOrderStatusAsStringAsync() { return (await this.GetOrderStatusAsync()).ToString(); } public async Task ReceiveReminderAsync(string reminderName, byte[] context, TimeSpan dueTime, TimeSpan period) { switch (reminderName) { case CustomerOrderReminderNames.FulfillOrderReminder: await this.FulfillOrderAsync(); CustomerOrderStatus orderStatus = await this.GetOrderStatusAsync(); if (orderStatus == CustomerOrderStatus.Shipped || orderStatus == CustomerOrderStatus.Canceled) { //Remove fulfill order reminder so Actor can be gargabe collected. IActorReminder orderReminder = this.GetReminder(CustomerOrderReminderNames.FulfillOrderReminder); await this.UnregisterReminderAsync(orderReminder); } break; default: // We should never arrive here normally. The system won't call reminders that don't exist. // But for our own sake in case we add a new reminder somewhere and forget to handle it, this will remind us. throw new InvalidOperationException("Unknown reminder: " + reminderName); } } /// /// Initializes CustomerOrderActor state. Because an order actor will only be activated /// once in this scenario and never used again, when we initiate the actor's state we /// change the order's status to "Confirmed," and do not need to check if the actor's /// state was already set to this. /// /// protected override async Task OnActivateAsync() { await InternalActivateAsync(this.ActorService.Context.CodePackageActivationContext, new ServiceProxyFactory()); CustomerOrderStatus orderStatusResult = await this.GetOrderStatusAsync(); if (orderStatusResult == CustomerOrderStatus.Unknown) { await this.StateManager.SetStateAsync>(OrderItemListPropertyName, new List()); await this.StateManager.SetStateAsync(RequestIdPropertyName, 0); await this.SetOrderStatusAsync(CustomerOrderStatus.New); } return; } /// /// Adding this method to support DI/Testing /// We need to do some work to create the actor object and make sure it is constructed completely /// In local testing we can inject the components we need, but in a real cluster /// those items are not established until the actor object is activated. Thus we need to /// have this method so that the tests can have the same init path as the actor would in prod /// /// public async Task InternalActivateAsync(ICodePackageActivationContext context, IServiceProxyFactory proxyFactory) { this.tokenSource = new CancellationTokenSource(); this.builder = new ServiceUriBuilder(context, InventoryServiceName); this.ServiceProxyFactory = proxyFactory; } /// /// Deactivates the actor object /// /// protected override Task OnDeactivateAsync() { this.tokenSource.Cancel(); this.tokenSource.Dispose(); return Task.FromResult(true); } /// /// This method takes in a list of CustomerOrderItem objects. Using a Service Proxy to access the Inventory Service, /// the method iterates onces through the order and tries to remove the quantity specified in the order from inventory. /// If the inventory has insufficient stock to remove the requested amount for a particular item, the entire order is /// marked as backordered and the item in question is added to a "backordered" item list, which is fulfilled in a separate /// method. /// /// In its current form, this application addresses the question of race conditions to remove the same item by making a rule /// that no order ever fails. While an item that is displayed in the store may not be available any longer by the time an order is placed, /// the automatic restock policy instituted in the Inventory Service means that our FulfillOrder method and its sub-methods can continue to /// query the Inventory Service on repeat (with a timer in between each cycle) until the order is fulfilled. /// /// /// The number of items put on backorder after fulfilling the order. internal async Task FulfillOrderAsync() { await this.SetOrderStatusAsync(CustomerOrderStatus.InProcess); IList orderedItems = await this.StateManager.GetStateAsync>(OrderItemListPropertyName); ActorEventSource.Current.ActorMessage(this, "Fullfilling customer order. ID: {0}. Items: {1}", this.Id.GetGuidId(), orderedItems.Count); foreach (CustomerOrderItem tempitem in orderedItems) { ActorEventSource.Current.Message("OrderContains:{0}", tempitem); } //We loop through the customer order list. //For every item that cannot be fulfilled, we add to backordered. foreach (CustomerOrderItem item in orderedItems.Where(x => x.FulfillmentRemaining > 0)) { IInventoryService inventoryService = this.ServiceProxyFactory.CreateServiceProxy(this.builder.ToUri(), item.ItemId.GetPartitionKey()); //First, check the item is listed in inventory. //This will avoid infinite backorder status. if ((await inventoryService.IsItemInInventoryAsync(item.ItemId, this.tokenSource.Token)) == false) { await this.SetOrderStatusAsync(CustomerOrderStatus.Canceled); return; } int numberItemsRemoved = await inventoryService.RemoveStockAsync( item.ItemId, item.Quantity, new CustomerOrderActorMessageId( new ActorId(this.Id.GetGuidId()), await this.StateManager.GetStateAsync(RequestIdPropertyName))); item.FulfillmentRemaining -= numberItemsRemoved; } IList items = await this.StateManager.GetStateAsync>(OrderItemListPropertyName); bool backordered = false; // Set the status appropriately foreach (CustomerOrderItem item in items) { if (item.FulfillmentRemaining > 0) { backordered = true; break; } } if (backordered) { await this.SetOrderStatusAsync(CustomerOrderStatus.Backordered); } else { await this.SetOrderStatusAsync(CustomerOrderStatus.Shipped); } ActorEventSource.Current.ActorMessage( this, "{0}; Fulfilled: {1}. Backordered: {2}", await this.GetOrderStatusAsStringAsync(), items.Count(x => x.FulfillmentRemaining == 0), items.Count(x => x.FulfillmentRemaining > 0)); long messageRequestId = await this.StateManager.GetStateAsync(RequestIdPropertyName); await this.StateManager.SetStateAsync(RequestIdPropertyName, ++messageRequestId); } private async Task GetOrderStatusAsync() { ConditionalValue orderStatusResult = await this.StateManager.TryGetStateAsync(OrderStatusPropertyName); if (orderStatusResult.HasValue) { return orderStatusResult.Value; } else { return CustomerOrderStatus.Unknown; } } private async Task SetOrderStatusAsync(CustomerOrderStatus orderStatus) { await this.StateManager.SetStateAsync(OrderStatusPropertyName, orderStatus); } } } ================================================ FILE: ReferenceApp/CustomerOrder.Actor/CustomerOrderReminderNames.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.Actor { internal static class CustomerOrderReminderNames { public const string FulfillOrderReminder = "FulfillOrderReminder"; } } ================================================ FILE: ReferenceApp/CustomerOrder.Actor/PackageRoot/Config/Settings.xml ================================================ 
================================================ FILE: ReferenceApp/CustomerOrder.Actor/PackageRoot/ServiceManifest.xml ================================================  CustomerOrder.Actor.exe ================================================ FILE: ReferenceApp/CustomerOrder.Actor/Program.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.Actor { using System; using System.Threading; using Microsoft.ServiceFabric.Actors.Runtime; public class Program { public static void Main(string[] args) { try { ActorRuntime.RegisterActorAsync(); Thread.Sleep(Timeout.Infinite); } catch (Exception e) { ActorEventSource.Current.ActorHostInitializationFailed(e.ToString()); throw; } } } } ================================================ FILE: ReferenceApp/CustomerOrder.Actor/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CustomerOrder")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CustomerOrder")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("5f0c7805-c91d-47e9-aede-946cadea1c8f")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: InternalsVisibleTo("CustomerOrder.UnitTests")] ================================================ FILE: ReferenceApp/CustomerOrder.Actor/packages.config ================================================  ================================================ FILE: ReferenceApp/CustomerOrder.Domain/CustomerOrder.Domain.csproj ================================================  Debug x64 {1E7E813F-43D3-4D0B-8546-5E1023873F28} Library Properties CustomerOrder.Domain CustomerOrder.Domain v4.5.2 512 true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/CustomerOrder.Domain/CustomerOrderItem.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.Domain { using System; using System.Runtime.Serialization; using Inventory.Domain; [DataContract] public sealed class CustomerOrderItem { public CustomerOrderItem(InventoryItemId itemId, int quantity) { this.ItemId = itemId; this.Quantity = quantity; this.FulfillmentRemaining = quantity; } [DataMember] public InventoryItemId ItemId { get; set; } [DataMember] public int Quantity { get; set; } [DataMember] public int FulfillmentRemaining { get; set; } public override string ToString() { return String.Format("ID: {0}, Quantity: {1}, Fulfillment Remaing: {2}", this.ItemId, this.Quantity, this.FulfillmentRemaining); } } } ================================================ FILE: ReferenceApp/CustomerOrder.Domain/CustomerOrderStatus.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.Domain { public enum CustomerOrderStatus { Unknown, New, Submitted, InProcess, Backordered, Shipped, Canceled, } } ================================================ FILE: ReferenceApp/CustomerOrder.Domain/ICustomerOrderActor.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.Domain { using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.ServiceFabric.Actors; public interface ICustomerOrderActor : IActor { Task GetOrderStatusAsStringAsync(); Task SubmitOrderAsync(IEnumerable orderList); } } ================================================ FILE: ReferenceApp/CustomerOrder.Domain/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CustomerOrder.Interfaces")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CustomerOrder.Interfaces")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("1e7e813f-43d3-4d0b-8546-5e1023873f28")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/CustomerOrder.Domain/app.config ================================================  ================================================ FILE: ReferenceApp/CustomerOrder.Domain/packages.config ================================================  ================================================ FILE: ReferenceApp/CustomerOrder.UnitTests/CustomerOrder.UnitTests.csproj ================================================  Debug AnyCPU {226B8D34-99CF-4172-87DC-E20B39030CC0} Library Properties CustomerOrder.UnitTests CustomerOrder.UnitTests v4.5.2 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages False UnitTest true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {5f0c7805-c91d-47e9-aede-946cadea1c8f} CustomerOrder.Actor {1e7e813f-43d3-4d0b-8546-5e1023873f28} CustomerOrder.Domain {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain {00e00484-bd00-40cd-b2cc-1cfa8e893972} Mocks ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll False ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True False False False False This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/CustomerOrder.UnitTests/CustomerOrderActorTests.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace CustomerOrder.UnitTests { using CustomerOrder.Actor; using CustomerOrder.Domain; using Inventory.Domain; using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Actors.Runtime; using Microsoft.VisualStudio.TestTools.UnitTesting; using Mocks; using System; using System.Collections.Generic; using System.Fabric; using System.Numerics; using System.Reflection; using System.Threading.Tasks; [TestClass] public class CustomerOrderActorTests { private const string OrderItemListPropertyName = "OrderList"; private const string OrderStatusPropertyName = "CustomerOrderStatus"; private const string RequestIdPropertyName = "RequestId"; private const string InventoryServiceName = "InventoryService"; private static ICodePackageActivationContext codePackageContext = new MockCodePackageActivationContext( "fabric:/someapp", "SomeAppType", "Code", "1.0.0.0", Guid.NewGuid().ToString(), @"C:\Log", @"C:\Temp", @"C:\Work", "ServiceManifest", "1.0.0.0" ); private static StatefulServiceContext statefulServiceContext = new StatefulServiceContext( new NodeContext("Test", new NodeId(new BigInteger(0), new BigInteger(0)), new BigInteger(0), "TestType", "localhost"), codePackageContext, "", new Uri("fabric:/testapp/testservice"), new byte[0], Guid.NewGuid(), 0); /// /// Tests FulfillOrder ships an order when all items are available from the InventoryService. /// /// [TestMethod] public async Task TestFulfillOrderSimple() { // The default mock inventory service behavior is to always complete an order. MockInventoryService inventoryService = new MockInventoryService(); MockServiceProxyFactory serviceProxyFactory = new MockServiceProxyFactory(); serviceProxyFactory.AssociateMockServiceAndName(new Uri("fabric:/someapp/" + InventoryServiceName), inventoryService); CustomerOrderActor target = await CreateCustomerOrderActor(serviceProxyFactory); await target.StateManager.SetStateAsync(RequestIdPropertyName, CustomerOrderStatus.Submitted); await target.StateManager.SetStateAsync(RequestIdPropertyName, 0); await target.StateManager.SetStateAsync>(OrderItemListPropertyName, new List() { new CustomerOrderItem(new InventoryItemId(), 4) }); await target.FulfillOrderAsync(); Assert.AreEqual(CustomerOrderStatus.Shipped, await target.StateManager.GetStateAsync(OrderStatusPropertyName)); } /// /// Tests FulfillOrder does not ship when not all items could be fulfilled by InventoryService. /// /// [TestMethod] public async Task TestFulfillOrderWithBackorder() { // instruct the mock inventory service to always return less quantity than requested // so that FulfillOrder always ends up in backordered status. MockInventoryService inventoryService = new MockInventoryService() { RemoveStockAsyncFunc = (itemId, quantity, cmid) => Task.FromResult(quantity - 1) }; MockServiceProxy serviceProxy = new MockServiceProxy(); serviceProxy.Supports(serviceUri => inventoryService); MockServiceProxyFactory serviceProxyFactory = new MockServiceProxyFactory(); serviceProxyFactory.AssociateMockServiceAndName(new Uri("fabric:/someapp/" + InventoryServiceName), inventoryService); CustomerOrderActor target = await CreateCustomerOrderActor(serviceProxyFactory); await target.StateManager.SetStateAsync(RequestIdPropertyName, CustomerOrderStatus.Submitted); await target.StateManager.SetStateAsync(RequestIdPropertyName, 0); await target.StateManager.SetStateAsync>(OrderItemListPropertyName, new List() { new CustomerOrderItem(new InventoryItemId(), 4) }); await target.FulfillOrderAsync(); Assert.AreEqual(CustomerOrderStatus.Backordered, await target.StateManager.GetStateAsync(OrderStatusPropertyName)); } /// /// Tests FulfillOrder completes a shipment after multiple iterations when a limited quantity is available from InventoryService. /// /// [TestMethod] public async Task TestFulfillOrderToCompletion() { int itemCount = 5; // instruct the mock inventory service to only fulfill one item each time // so that FulfillOrder has to make multiple iterations to complete an order MockInventoryService inventoryService = new MockInventoryService() { RemoveStockAsyncFunc = (itemId, quantity, cmid) => Task.FromResult(1) }; MockServiceProxy serviceProxy = new MockServiceProxy(); serviceProxy.Supports(serviceUri => inventoryService); MockServiceProxyFactory serviceProxyFactory = new MockServiceProxyFactory(); serviceProxyFactory.AssociateMockServiceAndName(new Uri("fabric:/someapp/" + InventoryServiceName), inventoryService); CustomerOrderActor target = await CreateCustomerOrderActor(serviceProxyFactory); await target.StateManager.SetStateAsync(RequestIdPropertyName, CustomerOrderStatus.Submitted); await target.StateManager.SetStateAsync(RequestIdPropertyName, 0); await target.StateManager.SetStateAsync>(OrderItemListPropertyName, new List() { new CustomerOrderItem(new InventoryItemId(), 5) }); for (int i = 0; i < itemCount - 1; ++i) { await target.FulfillOrderAsync(); Assert.AreEqual(CustomerOrderStatus.Backordered, await target.StateManager.GetStateAsync(OrderStatusPropertyName)); } await target.FulfillOrderAsync(); Assert.AreEqual(CustomerOrderStatus.Shipped, await target.StateManager.GetStateAsync(OrderStatusPropertyName)); } [TestMethod] public async Task TestFulfillOrderCancelled() { // instruct the mock inventory service to return 0 for all items to simulate items that don't exist. // and have it return false when asked if an item exists to make sure FulfillOrder doesn't get into // an infinite backorder loop. MockInventoryService inventoryService = new MockInventoryService() { IsItemInInventoryAsyncFunc = itemId => Task.FromResult(false), RemoveStockAsyncFunc = (itemId, quantity, cmid) => Task.FromResult(0) }; MockServiceProxy serviceProxy = new MockServiceProxy(); serviceProxy.Supports(serviceUri => inventoryService); MockServiceProxyFactory serviceProxyFactory = new MockServiceProxyFactory(); serviceProxyFactory.AssociateMockServiceAndName(new Uri("fabric:/someapp/" + InventoryServiceName), inventoryService); CustomerOrderActor target = await CreateCustomerOrderActor(serviceProxyFactory); await target.StateManager.SetStateAsync(RequestIdPropertyName, CustomerOrderStatus.Submitted); await target.StateManager.SetStateAsync(RequestIdPropertyName, 0); await target.StateManager.SetStateAsync>(OrderItemListPropertyName, new List() { new CustomerOrderItem(new InventoryItemId(), 5) }); await target.FulfillOrderAsync(); CustomerOrderStatus status = await target.StateManager.GetStateAsync(OrderStatusPropertyName); Assert.AreEqual(CustomerOrderStatus.Canceled, status); } private static async Task CreateCustomerOrderActor(MockServiceProxyFactory serviceProxyFactory) { try { CustomerOrderActor target = new CustomerOrderActor( new ActorService( context: statefulServiceContext, actorTypeInfo: ActorTypeInformation.Get(typeof(CustomerOrderActor)), stateManagerFactory: (actorBase, stateProvider) => new MockActorStateManager()), new ActorId(Guid.NewGuid())); await target.InternalActivateAsync(codePackageContext, serviceProxyFactory); return target; } catch (Exception e) { throw; } } } } ================================================ FILE: ReferenceApp/CustomerOrder.UnitTests/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CustomerOrder.UnitTests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CustomerOrder.UnitTests")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("226b8d34-99cf-4172-87dc-e20b39030cc0")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/CustomerOrder.UnitTests/app.config ================================================  ================================================ FILE: ReferenceApp/CustomerOrder.UnitTests/packages.config ================================================  ================================================ FILE: ReferenceApp/Inventory.Domain/IInventoryService.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Domain { using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Common; using Microsoft.ServiceFabric.Services.Remoting; public interface IInventoryService : IService { Task AddStockAsync(InventoryItemId itemId, int quantity); Task RemoveStockAsync(InventoryItemId itemId, int quantity, CustomerOrderActorMessageId messageId); Task IsItemInInventoryAsync(InventoryItemId itemId, CancellationToken cancellationToken); Task> GetCustomerInventoryAsync(CancellationToken cancellationToken); Task CreateInventoryItemAsync(InventoryItem item); } } ================================================ FILE: ReferenceApp/Inventory.Domain/Inventory.Domain.csproj ================================================  Debug x64 {7E9C2DFD-71A5-496D-AA4D-5EC53EAEB9AE} Library Properties Inventory.Domain Inventory.Domain v4.5.2 512 true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/Inventory.Domain/InventoryItem.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Domain { using System; [Serializable] public sealed class InventoryItem { public InventoryItem( string description, decimal price, int availableStock, int restockThreshold, int maxStockThreshold, InventoryItemId id = null, bool onReorder = false) { this.Id = id ?? new InventoryItemId(); this.Description = description; this.Price = price; this.AvailableStock = availableStock; this.RestockThreshold = restockThreshold; this.MaxStockThreshold = maxStockThreshold; this.OnReorder = onReorder; } /// /// Unique identifier for each item style /// public InventoryItemId Id { get; } /// /// Quantity in stock /// public int AvailableStock { get; private set; } /// /// Price /// public decimal Price { get; } /// /// Brief description of product for display on website /// public string Description { get; } /// /// Available stock at which we should reorder /// public int RestockThreshold { get; } /// /// Maximum number of units that can be in-stock at any time (due to physicial/logistical constraints in warehouses) /// public int MaxStockThreshold { get; } /// /// True if item is on reorder /// public bool OnReorder { get; set; } /// /// Returns an InventoryItemView object, which contains only external, customer-facing data about an item in inventory. /// /// public static implicit operator InventoryItemView(InventoryItem item) { return new InventoryItemView { Id = item.Id, Price = item.Price, Description = item.Description, CustomerAvailableStock = item.AvailableStock - item.RestockThreshold //Business logic: constraint to reduce overordering. }; } public override string ToString() { return string.Format( "Item {0}: {1} at a price of {2} with {3} available items at a restock threshold of {4} and with max stocking threshold of {5}.", this.Id, this.Description, this.Price, this.AvailableStock.ToString(), this.RestockThreshold.ToString(), this.MaxStockThreshold.ToString()); } /// /// Increments the quantity of a particular item in inventory. /// /// int: Returns the quantity that has been added to stock /// public int AddStock(int quantity) { int original = this.AvailableStock; // The quantity that the client is trying to add to stock is greater than what can be physically accommodated in a Fabrikam Warehouse if ((this.AvailableStock + quantity) > this.MaxStockThreshold) { // For now, this method only adds new units up maximum stock threshold. In an expanded version of this application, we //could include tracking for the remaining units and store information about overstock elsewhere. this.AvailableStock += (this.MaxStockThreshold - this.AvailableStock); } else { this.AvailableStock += quantity; } this.OnReorder = false; return this.AvailableStock - original; } /// /// Decrements the quantity of a particular item in inventory and ensures the restockThreshold hasn't /// been breached. If so, a RestockRequest is generated in CheckThreshold. /// /// If there is sufficient stock of an item, then the integer returned at the end of this call should be the same as quantityDesired. /// In the event that there is not sufficient stock available, the method will remove whatever stock is available and return that quantity to the client. /// In this case, it is the responsibility of the client to determine if the amount that is returned is the same as quantityDesired. /// It is invalid to pass in a negative number. /// /// /// int: Returns the number actually removed from stock. /// public int RemoveStock(int quantityDesired) { int removed = Math.Min(quantityDesired, this.AvailableStock); //Assumes quantityDesired is a positive integer this.AvailableStock -= removed; return removed; } } } ================================================ FILE: ReferenceApp/Inventory.Domain/InventoryItemId.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Domain { using System; using System.Runtime.Serialization; using Common; using Microsoft.ServiceFabric.Services.Client; [DataContract] public class InventoryItemId : IFormattable, IComparable, IComparable, IEquatable { [DataMember] private Guid id; public InventoryItemId() { this.id = Guid.NewGuid(); } public int CompareTo(object obj) { return this.id.CompareTo(((InventoryItemId) obj).id); } public int CompareTo(InventoryItemId other) { return this.id.CompareTo(other.id); } public bool Equals(InventoryItemId other) { return this.id.Equals(other.id); } public string ToString(string format, IFormatProvider formatProvider) { return this.id.ToString(format, formatProvider); } public ServicePartitionKey GetPartitionKey() { return new ServicePartitionKey(HashUtil.getLongHashCode(this.id.ToString())); } public static bool operator ==(InventoryItemId item1, InventoryItemId item2) { return item1.Equals(item2); } public static bool operator !=(InventoryItemId item1, InventoryItemId item2) { return !item1.Equals(item2); } public override bool Equals(object obj) { return (obj is InventoryItemId) ? this.id.Equals(((InventoryItemId) obj).id) : false; } public override int GetHashCode() { return this.id.GetHashCode(); } public override string ToString() { return this.id.ToString(); } public string ToString(string format) { return this.id.ToString(format); } } } ================================================ FILE: ReferenceApp/Inventory.Domain/InventoryItemView.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Domain { using System.Runtime.Serialization; //Guid will always be key to this value pair [DataContract] public sealed class InventoryItemView { [DataMember] public InventoryItemId Id { get; set; } [DataMember] public string Description { get; set; } [DataMember] public decimal Price { get; set; } [DataMember] public int CustomerAvailableStock { get; set; } } } ================================================ FILE: ReferenceApp/Inventory.Domain/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("InventoryService.Domain")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("InventoryService.Domain")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/Inventory.Domain/packages.config ================================================  ================================================ FILE: ReferenceApp/Inventory.Service/App.config ================================================  ================================================ FILE: ReferenceApp/Inventory.Service/AzureBackupStore.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Service { using System; using System.Collections.Generic; using System.Fabric.Description; using System.IO; using System.IO.Compression; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Blob; public class AzureBlobBackupManager : IBackupStore { private readonly CloudBlobClient cloudBlobClient; private CloudBlobContainer backupBlobContainer; private int MaxBackupsToKeep; private string PartitionTempDirectory; private string partitionId; private long backupFrequencyInSeconds; private long keyMin; private long keyMax; public AzureBlobBackupManager(ConfigurationSection configSection, string partitionId, long keymin, long keymax, string codePackageTempDirectory) { this.keyMin = keymin; this.keyMax = keymax; string backupAccountName = configSection.Parameters["BackupAccountName"].Value; string backupAccountKey = configSection.Parameters["PrimaryKeyForBackupTestAccount"].Value; string blobEndpointAddress = configSection.Parameters["BlobServiceEndpointAddress"].Value; this.backupFrequencyInSeconds = long.Parse(configSection.Parameters["BackupFrequencyInSeconds"].Value); this.MaxBackupsToKeep = int.Parse(configSection.Parameters["MaxBackupsToKeep"].Value); this.partitionId = partitionId; this.PartitionTempDirectory = Path.Combine(codePackageTempDirectory, partitionId); StorageCredentials storageCredentials = new StorageCredentials(backupAccountName, backupAccountKey); this.cloudBlobClient = new CloudBlobClient(new Uri(blobEndpointAddress), storageCredentials); this.backupBlobContainer = this.cloudBlobClient.GetContainerReference(this.partitionId); this.backupBlobContainer.CreateIfNotExists(); } long IBackupStore.backupFrequencyInSeconds { get { return this.backupFrequencyInSeconds; } } public async Task ArchiveBackupAsync(BackupInfo backupInfo, CancellationToken cancellationToken) { ServiceEventSource.Current.Message("AzureBlobBackupManager: Archive Called."); string fullArchiveDirectory = Path.Combine(this.PartitionTempDirectory, Guid.NewGuid().ToString("N")); DirectoryInfo fullArchiveDirectoryInfo = new DirectoryInfo(fullArchiveDirectory); fullArchiveDirectoryInfo.Create(); string blobName = string.Format("{0}_{1}_{2}_{3}", Guid.NewGuid().ToString("N"), this.keyMin, this.keyMax, "Backup.zip"); string fullArchivePath = Path.Combine(fullArchiveDirectory, "Backup.zip"); ZipFile.CreateFromDirectory(backupInfo.Directory, fullArchivePath, CompressionLevel.Fastest, false); DirectoryInfo backupDirectory = new DirectoryInfo(backupInfo.Directory); backupDirectory.Delete(true); CloudBlockBlob blob = this.backupBlobContainer.GetBlockBlobReference(blobName); await blob.UploadFromFileAsync(fullArchivePath, CancellationToken.None); DirectoryInfo tempDirectory = new DirectoryInfo(fullArchiveDirectory); tempDirectory.Delete(true); ServiceEventSource.Current.Message("AzureBlobBackupManager: UploadBackupFolderAsync: success."); } public async Task RestoreLatestBackupToTempLocation(CancellationToken cancellationToken) { ServiceEventSource.Current.Message("AzureBlobBackupManager: Download backup async called."); CloudBlockBlob lastBackupBlob = (await this.GetBackupBlobs(true)).First(); ServiceEventSource.Current.Message("AzureBlobBackupManager: Downloading {0}", lastBackupBlob.Name); string downloadId = Guid.NewGuid().ToString("N"); string zipPath = Path.Combine(this.PartitionTempDirectory, string.Format("{0}_Backup.zip", downloadId)); lastBackupBlob.DownloadToFile(zipPath, FileMode.CreateNew); string restorePath = Path.Combine(this.PartitionTempDirectory, downloadId); ZipFile.ExtractToDirectory(zipPath, restorePath); FileInfo zipInfo = new FileInfo(zipPath); zipInfo.Delete(); ServiceEventSource.Current.Message("AzureBlobBackupManager: Downloaded {0} in to {1}", lastBackupBlob.Name, restorePath); return restorePath; } public async Task DeleteBackupsAsync(CancellationToken cancellationToken) { if (this.backupBlobContainer.Exists()) { ServiceEventSource.Current.Message("AzureBlobBackupManager: Deleting old backups"); IEnumerable oldBackups = (await this.GetBackupBlobs(true)).Skip(this.MaxBackupsToKeep); foreach (CloudBlockBlob backup in oldBackups) { ServiceEventSource.Current.Message("AzureBlobBackupManager: Deleting {0}", backup.Name); await backup.DeleteAsync(cancellationToken); } } } private async Task> GetBackupBlobs(bool sorted) { IEnumerable blobs = this.backupBlobContainer.ListBlobs(); ServiceEventSource.Current.Message("AzureBlobBackupManager: Got {0} blobs", blobs.Count()); List itemizedBlobs = new List(); foreach (CloudBlockBlob cbb in blobs) { await cbb.FetchAttributesAsync(); itemizedBlobs.Add(cbb); } if (sorted) { return itemizedBlobs.OrderByDescending(x => x.Properties.LastModified); } else { return itemizedBlobs; } } } } ================================================ FILE: ReferenceApp/Inventory.Service/IBackupStore.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Service { using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; public interface IBackupStore { long backupFrequencyInSeconds { get; } Task ArchiveBackupAsync(BackupInfo backupInfo, CancellationToken cancellationToken); Task RestoreLatestBackupToTempLocation(CancellationToken cancellationToken); Task DeleteBackupsAsync(CancellationToken cancellationToken); } } ================================================ FILE: ReferenceApp/Inventory.Service/Inventory.Service.csproj ================================================  Debug x64 {714B1C61-FFA8-4A5E-8DD2-D0A290677293} Exe Properties Inventory.Service Inventory.Service v4.5.2 512 true True x64 true full false bin\Debug\ DEBUG;TRACE prompt 4 x64 pdbonly true bin\Release\ TRACE prompt 4 $(AdditionalFileItemNames);None ..\packages\Microsoft.Azure.KeyVault.Core.2.0.4\lib\net45\Microsoft.Azure.KeyVault.Core.dll True ..\packages\Microsoft.Data.Edm.5.8.2\lib\net40\Microsoft.Data.Edm.dll True ..\packages\Microsoft.Data.OData.5.8.2\lib\net40\Microsoft.Data.OData.dll True ..\packages\Microsoft.Data.Services.Client.5.8.2\lib\net40\Microsoft.Data.Services.Client.dll True ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\WindowsAzure.Storage.8.1.1\lib\net45\Microsoft.WindowsAzure.Storage.dll ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True ..\packages\System.Spatial.5.8.2\lib\net40\System.Spatial.dll True Designer {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain {a44fc2c5-6781-447e-80f5-7265b960b36a} RestockRequest.Domain {4162f266-d657-4143-aa62-626c10d23561} RestockRequestManager.Domain ================================================ FILE: ReferenceApp/Inventory.Service/InventoryService.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Service { using System; using System.Collections.Generic; using System.Fabric; using System.Fabric.Description; using System.IO; using System.Threading; using System.Threading.Tasks; using Common; using Inventory.Domain; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Communication.Runtime; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.ServiceFabric.Services.Remoting.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using RestockRequest.Domain; using RestockRequestManager.Domain; internal class InventoryService : StatefulService, IInventoryService { internal const string InventoryServiceType = "InventoryServiceType"; private const string InventoryItemDictionaryName = "inventoryItems"; private const string ActorMessageDictionaryName = "incomingMessages"; private const string RestockRequestManagerServiceName = "RestockRequestManager"; private const string RequestHistoryDictionaryName = "RequestHistory"; private const string BackupCountDictionaryName = "BackupCountingDictionary"; //private IReliableStateManager stateManager; private IBackupStore backupManager; //Set local or cloud backup, or none. Disabled is the default. Overridden by config. private BackupManagerType backupStorageType; /// /// This constructor is used in unit tests to inject a different state manager for unit testing. /// /// public InventoryService(StatefulServiceContext serviceContext) : this(serviceContext, (new ReliableStateManager(serviceContext))) { } public InventoryService(StatefulServiceContext context, IReliableStateManagerReplica stateManagerReplica) : base(context, stateManagerReplica) { } /// /// Used internally to generate inventory items and adds them to the ReliableDict we have. /// /// /// public async Task CreateInventoryItemAsync(InventoryItem item) { IReliableDictionary inventoryItems = await this.StateManager.GetOrAddAsync>(InventoryItemDictionaryName); using (ITransaction tx = this.StateManager.CreateTransaction()) { await inventoryItems.AddAsync(tx, item.Id, item); await tx.CommitAsync(); ServiceEventSource.Current.ServiceMessage(this, "Created inventory item: {0}", item); } return true; } /// /// Tries to add the given quantity to the inventory item with the given ID without going over the maximum quantity allowed for an item. /// /// /// /// The quantity actually added to the item. public async Task AddStockAsync(InventoryItemId itemId, int quantity) { IReliableDictionary inventoryItems = await this.StateManager.GetOrAddAsync>(InventoryItemDictionaryName); int quantityAdded = 0; ServiceEventSource.Current.ServiceMessage(this, "Received add stock request. Item: {0}. Quantity: {1}.", itemId, quantity); using (ITransaction tx = this.StateManager.CreateTransaction()) { // Try to get the InventoryItem for the ID in the request. ConditionalValue item = await inventoryItems.TryGetValueAsync(tx, itemId); // We can only update the stock for InventoryItems in the system - we are not adding new items here. if (item.HasValue) { // Update the stock quantity of the item. // This only updates the copy of the Inventory Item that's in local memory here; // It's not yet saved in the dictionary. quantityAdded = item.Value.AddStock(quantity); // We have to store the item back in the dictionary in order to actually save it. // This will then replicate the updated item for await inventoryItems.SetAsync(tx, item.Value.Id, item.Value); } // nothing will happen unless we commit the transaction! await tx.CommitAsync(); ServiceEventSource.Current.ServiceMessage( this, "Add stock complete. Item: {0}. Added: {1}. Total: {2}", item.Value.Id, quantityAdded, item.Value.AvailableStock); } return quantityAdded; } /// /// Removes the given quantity of stock from an in item in the inventory. /// /// /// int: Returns the quantity removed from stock. public async Task RemoveStockAsync(InventoryItemId itemId, int quantity, CustomerOrderActorMessageId amId) { ServiceEventSource.Current.ServiceMessage(this, "inside remove stock {0}|{1}", amId.GetHashCode(), amId.GetHashCode()); IReliableDictionary inventoryItems = await this.StateManager.GetOrAddAsync>(InventoryItemDictionaryName); IReliableDictionary recentRequests = await this.StateManager.GetOrAddAsync>(ActorMessageDictionaryName); IReliableDictionary> requestHistory = await this.StateManager.GetOrAddAsync>>(RequestHistoryDictionaryName); int removed = 0; ServiceEventSource.Current.ServiceMessage(this, "Received remove stock request. Item: {0}. Quantity: {1}.", itemId, quantity); using (ITransaction tx = this.StateManager.CreateTransaction()) { //first let's see if this is a duplicate request ConditionalValue previousRequest = await recentRequests.TryGetValueAsync(tx, amId); if (!previousRequest.HasValue) { //first time we've seen the request or it was a dupe from so long ago we have forgotten // Try to get the InventoryItem for the ID in the request. ConditionalValue item = await inventoryItems.TryGetValueAsync(tx, itemId); // We can only remove stock for InventoryItems in the system. if (item.HasValue) { // Update the stock quantity of the item. // This only updates the copy of the Inventory Item that's in local memory here; // It's not yet saved in the dictionary. removed = item.Value.RemoveStock(quantity); // We have to store the item back in the dictionary in order to actually save it. // This will then replicate the updated item await inventoryItems.SetAsync(tx, itemId, item.Value); //we also have to make a note that we have returned this result, so that we can protect //ourselves from stale or duplicate requests that come back later await requestHistory.SetAsync(tx, amId, new Tuple(itemId, removed)); ServiceEventSource.Current.ServiceMessage( this, "Removed stock complete. Item: {0}. Removed: {1}. Remaining: {2}", item.Value.Id, removed, item.Value.AvailableStock); } } else { //this is a duplicate request. We need to send back the result we already came up with and hope they get it this time //find the previous result and send it back ConditionalValue> previousResponse = await requestHistory.TryGetValueAsync(tx, amId); if (previousResponse.HasValue) { removed = previousResponse.Value.Item2; ServiceEventSource.Current.ServiceMessage( this, "Retrieved previous response for request {0}, from {1}, for Item {2} and quantity {3}", amId, previousRequest.Value, previousResponse.Value.Item1, previousResponse.Value.Item2); } else { //we've seen the request before but we don't have a record for what we responded, inconsistent state ServiceEventSource.Current.ServiceMessage( this, "Inconsistent State: recieved duplicate request {0} but don't have matching response in history", amId); this.Partition.ReportFault(System.Fabric.FaultType.Transient); } //note about duplicate Requests: technically if a duplicate request comes in and we have //sufficient invintory to return more now that we did previously, we could return more of the order and decrement //the difference to reduce the total number of round trips. This optimization is not currently implemented } //always update the datetime for the given request await recentRequests.SetAsync(tx, amId, DateTime.UtcNow); // nothing will happen unless we commit the transaction! ServiceEventSource.Current.Message("Committing Changes in Inventory Service"); await tx.CommitAsync(); ServiceEventSource.Current.Message("Inventory Service Changes Committed"); } ServiceEventSource.Current.Message("Removed {0} of item {1}", removed, itemId); return removed; } public async Task IsItemInInventoryAsync(InventoryItemId itemId, CancellationToken ct) { ServiceEventSource.Current.Message("checking item {0} to see if it is in inventory", itemId); IReliableDictionary inventoryItems = await this.StateManager.GetOrAddAsync>(InventoryItemDictionaryName); await this.PrintInventoryItemsAsync(inventoryItems, ct); using (ITransaction tx = this.StateManager.CreateTransaction()) { ConditionalValue item = await inventoryItems.TryGetValueAsync(tx, itemId); return item.HasValue; } } /// /// Retrieves a customer-specific view (defined in the InventoryItemView class in the Fabrikam Common namespace) /// of all items in the IReliableDictionary in InventoryService. Only items with a CustomerAvailableStock greater than /// zero are returned as a business logic constraint to reduce overordering. /// /// IEnumerable of InventoryItemView public async Task> GetCustomerInventoryAsync(CancellationToken ct) { IReliableDictionary inventoryItems = await this.StateManager.GetOrAddAsync>(InventoryItemDictionaryName); ServiceEventSource.Current.Message("Called GetCustomerInventory to return InventoryItemView"); await this.PrintInventoryItemsAsync(inventoryItems, ct); IList results = new List(); using (ITransaction tx = this.StateManager.CreateTransaction()) { ServiceEventSource.Current.Message("Generating item views for {0} items", await inventoryItems.GetCountAsync(tx)); IAsyncEnumerator> enumerator = (await inventoryItems.CreateEnumerableAsync(tx)).GetAsyncEnumerator(); while (await enumerator.MoveNextAsync(ct)) { if (enumerator.Current.Value.AvailableStock > 0) { results.Add(enumerator.Current.Value); } } } return results; } /// /// NOTE: This should not be used in published MVP code. /// This function allows us to remove inventory items from inventory. /// /// /// public async Task DeleteInventoryItemAsync(InventoryItemId itemId) { IReliableDictionary inventoryItems = await this.StateManager.GetOrAddAsync>(InventoryItemDictionaryName); using (ITransaction tx = this.StateManager.CreateTransaction()) { await inventoryItems.TryRemoveAsync(tx, itemId); await tx.CommitAsync(); } } /// /// Creates a new communication listener /// /// protected override IEnumerable CreateServiceReplicaListeners() { return new[] { new ServiceReplicaListener(context => this.CreateServiceRemotingListener(context)) }; } //Dataloss testing can be triggered via powershell. To do so, run the following commands as a script //Connect-ServiceFabricCluster //$s = "fabric:/WebReferenceApplication/InventoryService" //$p = Get-ServiceFabricApplication | Get-ServiceFabricService -ServiceName $s | Get-ServiceFabricPartition | Select -First 1 //$p | Invoke-ServiceFabricPartitionDataLoss -DataLossMode FullDataLoss -ServiceName $s protected override async Task OnDataLossAsync(RestoreContext restoreCtx, CancellationToken cancellationToken) { ServiceEventSource.Current.ServiceMessage(this, "OnDataLoss Invoked!"); this.SetupBackupManager(); try { string backupFolder; if (this.backupStorageType == BackupManagerType.None) { //since we have no backup configured, we return false to indicate //that state has not changed. This replica will become the basis //for future replica builds return false; } else { backupFolder = await this.backupManager.RestoreLatestBackupToTempLocation(cancellationToken); } ServiceEventSource.Current.ServiceMessage(this, "Restoration Folder Path " + backupFolder); RestoreDescription restoreRescription = new RestoreDescription(backupFolder, RestorePolicy.Force); await restoreCtx.RestoreAsync(restoreRescription, cancellationToken); ServiceEventSource.Current.ServiceMessage(this, "Restore completed"); DirectoryInfo tempRestoreDirectory = new DirectoryInfo(backupFolder); tempRestoreDirectory.Delete(true); return true; } catch (Exception e) { ServiceEventSource.Current.ServiceMessage(this, "Restoration failed: " + "{0} {1}" + e.GetType() + e.Message); throw; } } protected override Task RunAsync(CancellationToken cancellationToken) { try { ServiceEventSource.Current.ServiceMessage(this, "inside RunAsync for Inventory Service"); return Task.WhenAll( this.PeriodicInventoryCheck(cancellationToken), this.PeriodicOldMessageTrimming(cancellationToken), this.PeriodicTakeBackupAsync(cancellationToken)); } catch (Exception e) { ServiceEventSource.Current.ServiceMessage(this, "RunAsync Failed, {0}", e); throw; } } private async Task BackupCallbackAsync(BackupInfo backupInfo, CancellationToken cancellationToken) { ServiceEventSource.Current.ServiceMessage(this, "Inside backup callback for replica {0}|{1}", this.Context.PartitionId, this.Context.ReplicaId); long totalBackupCount; IReliableDictionary backupCountDictionary = await this.StateManager.GetOrAddAsync>(BackupCountDictionaryName); using (ITransaction tx = this.StateManager.CreateTransaction()) { ConditionalValue value = await backupCountDictionary.TryGetValueAsync(tx, "backupCount"); if (!value.HasValue) { totalBackupCount = 0; } else { totalBackupCount = value.Value; } await backupCountDictionary.SetAsync(tx, "backupCount", ++totalBackupCount); await tx.CommitAsync(); } ServiceEventSource.Current.Message("Backup count dictionary updated, total backup count is {0}", totalBackupCount); try { ServiceEventSource.Current.ServiceMessage(this, "Archiving backup"); await this.backupManager.ArchiveBackupAsync(backupInfo, cancellationToken); ServiceEventSource.Current.ServiceMessage(this, "Backup archived"); } catch (Exception e) { ServiceEventSource.Current.ServiceMessage(this, "Archive of backup failed: Source: {0} Exception: {1}", backupInfo.Directory, e.Message); } await this.backupManager.DeleteBackupsAsync(cancellationToken); ServiceEventSource.Current.Message("Backups deleted"); return true; } private async Task PrintInventoryItemsAsync(IReliableDictionary inventoryItems, CancellationToken cancellationToken) { using (ITransaction tx = this.StateManager.CreateTransaction()) { ServiceEventSource.Current.Message("Printing Inventory for {0} items:", await inventoryItems.GetCountAsync(tx)); IAsyncEnumerator> enumerator = (await inventoryItems.CreateEnumerableAsync(tx)).GetAsyncEnumerator(); while (await enumerator.MoveNextAsync(cancellationToken)) { ServiceEventSource.Current.Message("ID:{0}|Item:{1}", enumerator.Current.Key, enumerator.Current.Value); } } } private async Task PeriodicOldMessageTrimming(CancellationToken cancellationToken) { IReliableDictionary recentRequests = await this.StateManager.GetOrAddAsync>(ActorMessageDictionaryName); IReliableDictionary> requestHistory = await this.StateManager.GetOrAddAsync>>(RequestHistoryDictionaryName); while (!cancellationToken.IsCancellationRequested) { using (ITransaction tx = this.StateManager.CreateTransaction()) { IAsyncEnumerator> enumerator = (await recentRequests.CreateEnumerableAsync(tx)).GetAsyncEnumerator(); while (await enumerator.MoveNextAsync(cancellationToken)) { //if we have a record of a message that is older than 2 hours from current time, then remove that record //from both of the stale message tracking dictionaries. if (enumerator.Current.Value < (DateTime.UtcNow.AddHours(-2))) { await recentRequests.TryRemoveAsync(tx, enumerator.Current.Key); await requestHistory.TryRemoveAsync(tx, enumerator.Current.Key); } } await tx.CommitAsync(); } //sleep for 5 minutes then scan again await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken); } } private async Task PeriodicInventoryCheck(CancellationToken cancellationToken) { IReliableDictionary inventoryItems = await this.StateManager.GetOrAddAsync>(InventoryItemDictionaryName); while (true) { cancellationToken.ThrowIfCancellationRequested(); IList items = new List(); using (ITransaction tx = this.StateManager.CreateTransaction()) { ServiceEventSource.Current.ServiceMessage(this, "Checking inventory stock for {0} items.", await inventoryItems.GetCountAsync(tx)); IAsyncEnumerator> enumerator = (await inventoryItems.CreateEnumerableAsync(tx)).GetAsyncEnumerator(); while (await enumerator.MoveNextAsync(cancellationToken)) { InventoryItem item = enumerator.Current.Value; //Check if stock is below restockThreshold and if the item is not already on reorder if ((item.AvailableStock <= item.RestockThreshold) && !item.OnReorder) { items.Add(enumerator.Current.Value); } } } foreach (InventoryItem item in items) { cancellationToken.ThrowIfCancellationRequested(); try { ServiceUriBuilder builder = new ServiceUriBuilder(RestockRequestManagerServiceName); IRestockRequestManager restockRequestManagerClient = ServiceProxy.Create( builder.ToUri(), new ServicePartitionKey()); // we reduce the quantity passed in to RestockRequest to ensure we don't overorder RestockRequest newRequest = new RestockRequest(item.Id, (item.MaxStockThreshold - item.AvailableStock)); InventoryItem updatedItem = new InventoryItem( item.Description, item.Price, item.AvailableStock, item.RestockThreshold, item.MaxStockThreshold, item.Id, true); // TODO: this call needs to be idempotent in case we fail to update the InventoryItem after this completes. await restockRequestManagerClient.AddRestockRequestAsync(newRequest); // Write operations take an exclusive lock on an item, which means we can't do anything else with that item while the transaction is open. // If something blocks before the transaction is committed, the open transaction on the item will prevent all operations on it, including reads. // Once the transaction commits, the lock is released and other operations on the item can proceed. // Operations on the transaction all have timeouts to prevent deadlocking an item, // but we should do as little work inside the transaction as possible that is not related to the transaction itself. using (ITransaction tx = this.StateManager.CreateTransaction()) { await inventoryItems.TryUpdateAsync(tx, item.Id, updatedItem, item); await tx.CommitAsync(); } ServiceEventSource.Current.ServiceMessage( this, "Restock order placed. Item ID: {0}. Quantity: {1}", newRequest.ItemId, newRequest.Quantity); } catch (Exception e) { ServiceEventSource.Current.ServiceMessage(this, "Failed to place restock order for item {0}. {1}", item.Id, e.ToString()); } } await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); } } private async Task PeriodicTakeBackupAsync(CancellationToken cancellationToken) { long backupsTaken = 0; this.SetupBackupManager(); while (true) { cancellationToken.ThrowIfCancellationRequested(); if (this.backupStorageType == BackupManagerType.None) { break; } else { await Task.Delay(TimeSpan.FromSeconds(this.backupManager.backupFrequencyInSeconds)); BackupDescription backupDescription = new BackupDescription(BackupOption.Full, this.BackupCallbackAsync); await this.BackupAsync(backupDescription, TimeSpan.FromHours(1), cancellationToken); backupsTaken++; ServiceEventSource.Current.ServiceMessage(this, "Backup {0} taken", backupsTaken); } } } private void SetupBackupManager() { string partitionId = this.Context.PartitionId.ToString("N"); long minKey = ((Int64RangePartitionInformation) this.Partition.PartitionInfo).LowKey; long maxKey = ((Int64RangePartitionInformation) this.Partition.PartitionInfo).HighKey; if (this.Context.CodePackageActivationContext != null) { ICodePackageActivationContext codePackageContext = this.Context.CodePackageActivationContext; ConfigurationPackage configPackage = codePackageContext.GetConfigurationPackageObject("Config"); ConfigurationSection configSection = configPackage.Settings.Sections["Inventory.Service.Settings"]; string backupSettingValue = configSection.Parameters["BackupMode"].Value; if (string.Equals(backupSettingValue, "none", StringComparison.InvariantCultureIgnoreCase)) { this.backupStorageType = BackupManagerType.None; } else if (string.Equals(backupSettingValue, "azure", StringComparison.InvariantCultureIgnoreCase)) { this.backupStorageType = BackupManagerType.Azure; ConfigurationSection azureBackupConfigSection = configPackage.Settings.Sections["Inventory.Service.BackupSettings.Azure"]; this.backupManager = new AzureBlobBackupManager(azureBackupConfigSection, partitionId, minKey, maxKey, codePackageContext.TempDirectory); } else if (string.Equals(backupSettingValue, "local", StringComparison.InvariantCultureIgnoreCase)) { this.backupStorageType = BackupManagerType.Local; ConfigurationSection localBackupConfigSection = configPackage.Settings.Sections["Inventory.Service.BackupSettings.Local"]; this.backupManager = new DiskBackupManager(localBackupConfigSection, partitionId, minKey, maxKey, codePackageContext.TempDirectory); } else { throw new ArgumentException("Unknown backup type"); } ServiceEventSource.Current.ServiceMessage(this, "Backup Manager Set Up"); } } private enum BackupManagerType { Azure, Local, None }; } } ================================================ FILE: ReferenceApp/Inventory.Service/LocalBackupStore.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Service { using System; using System.Collections.Generic; using System.Fabric.Description; using System.IO; using System.IO.Compression; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; public class DiskBackupManager : IBackupStore { private string PartitionArchiveFolder; private string PartitionTempDirectory; private long backupFrequencyInSeconds; private int MaxBackupsToKeep; private long keyMin; private long keyMax; public DiskBackupManager(ConfigurationSection configSection, string partitionId, long keymin, long keymax, string codePackageTempDirectory) { this.keyMin = keymin; this.keyMax = keymax; string BackupArchivalPath = configSection.Parameters["BackupArchivalPath"].Value; this.backupFrequencyInSeconds = long.Parse(configSection.Parameters["BackupFrequencyInSeconds"].Value); this.MaxBackupsToKeep = int.Parse(configSection.Parameters["MaxBackupsToKeep"].Value); this.PartitionArchiveFolder = Path.Combine(BackupArchivalPath, "Backups", partitionId); this.PartitionTempDirectory = Path.Combine(codePackageTempDirectory, partitionId); ServiceEventSource.Current.Message( "DiskBackupManager constructed IntervalinSec:{0}, archivePath:{1}, tempPath:{2}, backupsToKeep:{3}", this.backupFrequencyInSeconds, this.PartitionArchiveFolder, this.PartitionTempDirectory, this.MaxBackupsToKeep); } long IBackupStore.backupFrequencyInSeconds { get { return this.backupFrequencyInSeconds; } } public Task ArchiveBackupAsync(BackupInfo backupInfo, CancellationToken cancellationToken) { string fullArchiveDirectory = Path.Combine( this.PartitionArchiveFolder, string.Format("{0}_{1}_{2}", Guid.NewGuid().ToString("N"), this.keyMin, this.keyMax)); DirectoryInfo dirInfo = new DirectoryInfo(fullArchiveDirectory); dirInfo.Create(); string fullArchivePath = Path.Combine(fullArchiveDirectory, "Backup.zip"); ZipFile.CreateFromDirectory(backupInfo.Directory, fullArchivePath, CompressionLevel.Fastest, false); DirectoryInfo backupDirectory = new DirectoryInfo(backupInfo.Directory); backupDirectory.Delete(true); return Task.FromResult(true); } public Task RestoreLatestBackupToTempLocation(CancellationToken cancellationToken) { ServiceEventSource.Current.Message("Restoring backup to temp source:{0} destination:{1}", this.PartitionArchiveFolder, this.PartitionTempDirectory); DirectoryInfo dirInfo = new DirectoryInfo(this.PartitionArchiveFolder); string backupZip = dirInfo.GetDirectories().OrderByDescending(x => x.LastWriteTime).First().FullName; string zipPath = Path.Combine(backupZip, "Backup.zip"); ServiceEventSource.Current.Message("latest zip backup is {0}", zipPath); DirectoryInfo directoryInfo = new DirectoryInfo(this.PartitionTempDirectory); if (directoryInfo.Exists) { directoryInfo.Delete(true); } directoryInfo.Create(); ZipFile.ExtractToDirectory(zipPath, this.PartitionTempDirectory); ServiceEventSource.Current.Message("Zip backup {0} extracted to {1}", zipPath, this.PartitionTempDirectory); return Task.FromResult(this.PartitionTempDirectory); } public async Task DeleteBackupsAsync(CancellationToken cancellationToken) { await Task.Run( () => { ServiceEventSource.Current.Message("deleting old backups"); if (!Directory.Exists(this.PartitionArchiveFolder)) { //Nothing to delete; Backups may not even have been created for the partition return; } DirectoryInfo dirInfo = new DirectoryInfo(this.PartitionArchiveFolder); IEnumerable oldBackups = dirInfo.GetDirectories().OrderByDescending(x => x.LastWriteTime).Skip(this.MaxBackupsToKeep); foreach (DirectoryInfo oldBackup in oldBackups) { ServiceEventSource.Current.Message("Deleting old backup {0}", oldBackup.FullName); oldBackup.Delete(true); } ServiceEventSource.Current.Message("Old backups deleted"); return; }, cancellationToken); } } } ================================================ FILE: ReferenceApp/Inventory.Service/PackageRoot/Config/Settings.xml ================================================ 
================================================ FILE: ReferenceApp/Inventory.Service/PackageRoot/ServiceManifest.xml ================================================  Inventory.Service.exe ================================================ FILE: ReferenceApp/Inventory.Service/Program.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Service { using System; using System.Diagnostics; using System.Threading; using Microsoft.ServiceFabric.Services.Runtime; public class Program { public static void Main(string[] args) { try { ServiceRuntime.RegisterServiceAsync(InventoryService.InventoryServiceType, (context) => new InventoryService(context)).GetAwaiter().GetResult(); ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(InventoryService).Name); Thread.Sleep(Timeout.Infinite); } catch (Exception e) { ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString()); throw; } } } } ================================================ FILE: ReferenceApp/Inventory.Service/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("InventoryService")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("InventoryService")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("714b1c61-ffa8-4a5e-8dd2-d0a290677293")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: InternalsVisibleTo("Inventory.UnitTests")] ================================================ FILE: ReferenceApp/Inventory.Service/ServiceEventSource.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Service { using System; using System.Diagnostics.Tracing; using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Runtime; [EventSource(Name = "MyCompany-Web_UIApplication-InventoryService")] internal sealed class ServiceEventSource : EventSource { private const int MessageEventId = 1; // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. private const int ServiceMessageEventId = 2; private const int ServiceTypeRegisteredEventId = 3; private const int ServiceHostInitializationFailedEventId = 4; // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity. // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities, // and other statistics. private const int ServiceRequestStartEventId = 5; private const int ServiceRequestStopEventId = 6; private const int ServiceRequestFailedEventId = 7; public static readonly ServiceEventSource Current = new ServiceEventSource(); static ServiceEventSource() { // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. // This problem will be fixed in .NET Framework 4.6.2. Task.Run(() => { }).Wait(); } // Instance constructor is private to enforce singleton semantics private ServiceEventSource() : base() { } // Define an instance method for each event you want to record and apply an [Event] attribute to it. // The method name is the name of the event. // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). // Put [NonEvent] attribute on all methods that do not define an event. // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx [NonEvent] public void Message(string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); this.Message(finalMessage); } } [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] public void Message(string message) { if (this.IsEnabled()) { this.WriteEvent(MessageEventId, message); } } [NonEvent] public void ServiceMessage(StatefulService service, string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); this.ServiceMessage( service.Context.ServiceName.ToString(), service.Context.ServiceTypeName, service.Context.ReplicaId, service.Context.PartitionId, service.Context.CodePackageActivationContext.ApplicationName, service.Context.CodePackageActivationContext.ApplicationTypeName, service.Context.NodeContext.NodeName, finalMessage); } } [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)] public void ServiceTypeRegistered(int hostProcessId, string serviceType) { this.WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType); } [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)] public void ServiceHostInitializationFailed(string exception) { this.WriteEvent(ServiceHostInitializationFailedEventId, exception); } [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)] public void ServiceRequestStart(string requestTypeName) { this.WriteEvent(ServiceRequestStartEventId, requestTypeName); } [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)] public void ServiceRequestStop(string requestTypeName) { this.WriteEvent(ServiceRequestStopEventId, requestTypeName); } [Event(ServiceRequestFailedEventId, Level = EventLevel.Error, Message = "Service request '{0}' failed", Keywords = Keywords.Requests)] public void ServiceRequestFailed(string requestTypeName, string exception) { this.WriteEvent(ServiceRequestFailedEventId, exception); } [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")] private void ServiceMessage( string serviceName, string serviceTypeName, long replicaOrInstanceId, Guid partitionId, string applicationName, string applicationTypeName, string nodeName, string message) { this.WriteEvent( ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message); } // Event keywords can be used to categorize events. // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. public static class Keywords { public const EventKeywords Requests = (EventKeywords) 0x1L; public const EventKeywords ServiceInitialization = (EventKeywords) 0x2L; } } } ================================================ FILE: ReferenceApp/Inventory.Service/StatefulServiceParameters.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.Service { using System; using System.Fabric; internal class StatefulServiceParameters { public StatefulServiceParameters( CodePackageActivationContext codePackageActivationContext, byte[] initializationData, Guid partitionId, Uri serviceName, string serviceTypeName, long replicaId) { this.CodePackageActivationContext = codePackageActivationContext; this.InitializationData = initializationData; this.PartitionId = partitionId; this.ServiceName = serviceName; this.ServiceTypeName = serviceTypeName; this.ReplicaId = replicaId; } public CodePackageActivationContext CodePackageActivationContext { get; } public byte[] InitializationData { get; } public Guid PartitionId { get; } public long ReplicaId { get; } public Uri ServiceName { get; } public string ServiceTypeName { get; } } } ================================================ FILE: ReferenceApp/Inventory.Service/packages.config ================================================  ================================================ FILE: ReferenceApp/Inventory.UnitTests/Inventory.UnitTests.csproj ================================================  Debug AnyCPU {71E58E09-BEE4-4B19-BCF7-4C9BD71514FB} Library Properties Inventory.UnitTests Inventory.UnitTests v4.5.2 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages False UnitTest true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True {9EC0063F-489E-43FE-94B5-BF5F89977CD3} Common {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain {714b1c61-ffa8-4a5e-8dd2-d0a290677293} Inventory.Service {00e00484-bd00-40cd-b2cc-1cfa8e893972} Mocks {a44fc2c5-6781-447e-80f5-7265b960b36a} RestockRequest.Domain False False False False ================================================ FILE: ReferenceApp/Inventory.UnitTests/InventoryServiceTests.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Inventory.UnitTests { using Common; using Inventory.Domain; using Inventory.Service; using Microsoft.VisualStudio.TestTools.UnitTesting; using Mocks; using System; using System.Fabric; using System.Threading; using System.Threading.Tasks; [TestClass] public class InventoryServiceTests { private static ICodePackageActivationContext codePackageContext = new MockCodePackageActivationContext( "fabric:/someapp", "SomeAppType", "Code", "1.0.0.0", Guid.NewGuid().ToString(), @"C:\Log", @"C:\Temp", @"C:\Work", "ServiceManifest", "1.0.0.0" ); StatefulServiceContext statefulServiceContext = new StatefulServiceContext( new NodeContext("Node0", new NodeId(0, 1), 0, "NodeType1", "TEST.MACHINE"), codePackageContext, InventoryService.InventoryServiceType, new Uri("fabric:/someapp/someservice"), null, Guid.NewGuid(), long.MaxValue ); [TestMethod] public async Task TestCreateAndIsItemInInventoryAsync() { MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(statefulServiceContext, stateManager); InventoryItem expected = new InventoryItem("test", 1, 10, 1, 10); await target.CreateInventoryItemAsync(expected); bool resultTrue = await target.IsItemInInventoryAsync(expected.Id, CancellationToken.None); bool resultFalse = await target.IsItemInInventoryAsync(new InventoryItemId(), CancellationToken.None); Assert.IsTrue(resultTrue); Assert.IsFalse(resultFalse); } [TestMethod] public async Task TestAddStock() { int expectedQuantity = 10; int quantityToAdd = 3; MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(statefulServiceContext, stateManager); InventoryItem item = new InventoryItem("test", 1, expectedQuantity - quantityToAdd, 1, expectedQuantity); RestockRequest.Domain.RestockRequest request = new RestockRequest.Domain.RestockRequest(item.Id, quantityToAdd); await target.CreateInventoryItemAsync(item); int actualAdded = await target.AddStockAsync(request.ItemId, quantityToAdd); Assert.AreEqual(quantityToAdd, actualAdded); Assert.AreEqual(item.AvailableStock, expectedQuantity); } [TestMethod] public async Task TestRemoveStock() { int expectedQuantity = 5; int quantityToRemove = 3; MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(statefulServiceContext, stateManager); InventoryItem item = new InventoryItem("test", 1, expectedQuantity + quantityToRemove, 1, expectedQuantity); await target.CreateInventoryItemAsync(item); int actualRemoved = await target.RemoveStockAsync(item.Id, quantityToRemove, CustomerOrderActorMessageId.GetRandom()); Assert.AreEqual(quantityToRemove, actualRemoved); Assert.AreEqual(expectedQuantity, item.AvailableStock); } [TestMethod] public async Task TestRemoveStockWithDuplicateRequest() { int totalStartingStock = 8; int expectedQuantity = 5; int quantityToRemove = 3; MockReliableStateManager stateManager = new MockReliableStateManager(); InventoryService target = new InventoryService(statefulServiceContext, stateManager); InventoryItem item = new InventoryItem("test", 1, totalStartingStock, 1, expectedQuantity); await target.CreateInventoryItemAsync(item); CustomerOrderActorMessageId cmid = CustomerOrderActorMessageId.GetRandom(); int actualRemoved = await target.RemoveStockAsync(item.Id, quantityToRemove, cmid); Assert.AreEqual(quantityToRemove, actualRemoved); Assert.AreEqual(expectedQuantity, item.AvailableStock); //save the current availablestock so we can check to be sure it doesn't change int priorAvailableStock = item.AvailableStock; //but now lets say that the reciever didn't get the response and so sends the exact same request again int actualRemoved2 = await target.RemoveStockAsync(item.Id, quantityToRemove, cmid); //in this case the response for the amount removed should be the same Assert.AreEqual(actualRemoved, actualRemoved2); //also, since the request was a duplicate the remaining invintory should be the same as it was before. Assert.AreEqual(item.AvailableStock, priorAvailableStock); } } } ================================================ FILE: ReferenceApp/Inventory.UnitTests/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Inventory.UnitTests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Inventory.UnitTests")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("71e58e09-bee4-4b19-bcf7-4c9bd71514fb")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/Inventory.UnitTests/app.config ================================================  ================================================ FILE: ReferenceApp/Inventory.UnitTests/packages.config ================================================  ================================================ FILE: ReferenceApp/Mocks/MockActorStateManager.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using Microsoft.ServiceFabric.Actors.Runtime; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Data.Notifications; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Fabric; using System.Threading; using System.Threading.Tasks; public class MockActorStateManager : IActorStateManager { private ConcurrentDictionary store = new ConcurrentDictionary(); public Task AddOrUpdateStateAsync(string stateName, T addValue, Func updateValueFactory, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task AddStateAsync(string stateName, T value, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task ContainsStateAsync(string stateName, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task GetOrAddStateAsync(string stateName, T value, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task GetStateAsync(string stateName, CancellationToken cancellationToken = default(CancellationToken)) { object result; this.store.TryGetValue(stateName, out result); return Task.FromResult((T)result); } public Task> GetStateNamesAsync(CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task RemoveStateAsync(string stateName, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task SetStateAsync(string stateName, T value, CancellationToken cancellationToken = default(CancellationToken)) { this.store.AddOrUpdate(stateName, value, (key, oldvalue) => value); return Task.FromResult(true); } public Task TryAddStateAsync(string stateName, T value, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task> TryGetStateAsync(string stateName, CancellationToken cancellationToken = default(CancellationToken)) { object item; bool result = this.store.TryGetValue(stateName, out item); return Task.FromResult(new ConditionalValue(result, (T)item)); } public Task TryRemoveStateAsync(string stateName, CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task ClearCacheAsync(CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } public Task SaveStateAsync(CancellationToken cancellationToken = default(CancellationToken)) { throw new NotImplementedException(); } } } ================================================ FILE: ReferenceApp/Mocks/MockAsyncEnumerable.cs ================================================ namespace Mocks { using Microsoft.ServiceFabric.Data; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; /// /// Simple wrapper for a synchronous IEnumerable of T. /// /// internal class MockAsyncEnumerable : IAsyncEnumerable { private IEnumerable enumerable; public MockAsyncEnumerable(IEnumerable enumerable) { this.enumerable = enumerable; } public IAsyncEnumerator GetAsyncEnumerator() { return new MockAsyncEnumerator(this.enumerable.GetEnumerator()); } } /// /// Simply wrapper for a synchronous IEnumerator of T. /// /// internal class MockAsyncEnumerator : IAsyncEnumerator { private readonly IEnumerator enumerator; public MockAsyncEnumerator(IEnumerator enumerator) { this.enumerator = enumerator; } public T Current { get { return this.enumerator.Current; } } public void Dispose() { this.enumerator.Dispose(); } public Task MoveNextAsync(CancellationToken cancellationToken) { return Task.FromResult(this.enumerator.MoveNext()); } public void Reset() { this.enumerator.Reset(); } } } ================================================ FILE: ReferenceApp/Mocks/MockCodePackageActivationContext.cs ================================================ namespace Mocks { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Fabric; using System.Fabric.Description; using System.Fabric.Health; public class MockCodePackageActivationContext : ICodePackageActivationContext { public string ApplicationName { get; private set; } public string ApplicationTypeName { get; private set; } public string CodePackageName { get; private set; } public string CodePackageVersion { get; private set; } public string ContextId { get; private set; } public string LogDirectory { get; private set; } public string TempDirectory { get; private set; } public string WorkDirectory { get; private set; } private string ServiceManifetName { get; set; } private string ServiceManifestVersion { get; set; } public event EventHandler> CodePackageAddedEvent; public event EventHandler> CodePackageModifiedEvent; public event EventHandler> CodePackageRemovedEvent; public event EventHandler> ConfigurationPackageAddedEvent; public event EventHandler> ConfigurationPackageModifiedEvent; public event EventHandler> ConfigurationPackageRemovedEvent; public event EventHandler> DataPackageAddedEvent; public event EventHandler> DataPackageModifiedEvent; public event EventHandler> DataPackageRemovedEvent; public ApplicationPrincipalsDescription GetApplicationPrincipals() { throw new NotImplementedException(); } public IList GetCodePackageNames() { return new List() { this.CodePackageName }; } public CodePackage GetCodePackageObject(string packageName) { throw new NotImplementedException(); } public IList GetConfigurationPackageNames() { return new List() { "" }; } public ConfigurationPackage GetConfigurationPackageObject(string packageName) { throw new NotImplementedException(); } public IList GetDataPackageNames() { return new List() { "" }; } public DataPackage GetDataPackageObject(string packageName) { throw new NotImplementedException(); } public EndpointResourceDescription GetEndpoint(string endpointName) { throw new NotImplementedException(); } public KeyedCollection GetEndpoints() { throw new NotImplementedException(); } public KeyedCollection GetServiceGroupTypes() { throw new NotImplementedException(); } public string GetServiceManifestName() { return this.ServiceManifetName; } public string GetServiceManifestVersion() { return this.ServiceManifestVersion; } public KeyedCollection GetServiceTypes() { throw new NotImplementedException(); } public void ReportApplicationHealth(HealthInformation healthInformation) { throw new NotImplementedException(); } public void ReportDeployedServicePackageHealth(HealthInformation healthInformation) { throw new NotImplementedException(); } public void ReportDeployedApplicationHealth(HealthInformation healthInformation) { throw new NotImplementedException(); } public MockCodePackageActivationContext( string ApplicationName, string ApplicationTypeName, string CodePackageName, string CodePackageVersion, string Context, string LogDirectory, string TempDirectory, string WorkDirectory, string ServiceManifestName, string ServiceManifestVersion) { this.ApplicationName = ApplicationName; this.ApplicationTypeName = ApplicationTypeName; this.CodePackageName = CodePackageName; this.CodePackageVersion = CodePackageVersion; this.ContextId = Context; this.LogDirectory = LogDirectory; this.TempDirectory = TempDirectory; this.WorkDirectory = WorkDirectory; } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: dispose managed state (managed objects). } // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. // TODO: set large fields to null. disposedValue = true; } } // This code added to correctly implement the disposable pattern. public void Dispose() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); // TODO: uncomment the following line if the finalizer is overridden above. // GC.SuppressFinalize(this); } #endregion } } ================================================ FILE: ReferenceApp/Mocks/MockInventoryService.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using Common; using Inventory.Domain; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; public class MockInventoryService : IInventoryService { public MockInventoryService() { this.AddStockAsyncFunc = (itemId, quantity) => Task.FromResult(quantity); this.RemoveStockAsyncFunc = (itemId, quantity, amId) => Task.FromResult(quantity); this.IsItemInInventoryAsyncFunc = (itemId) => Task.FromResult(true); this.GetCustomerInventoryAsyncFunc = () => Task.FromResult>(new List() { new InventoryItemView() }); this.CreateInventoryItemAsyncFunc = item => Task.FromResult(true); } public Func> AddStockAsyncFunc { get; set; } public Func> CreateInventoryItemAsyncFunc { get; set; } public Func>> GetCustomerInventoryAsyncFunc { get; set; } public Func> IsItemInInventoryAsyncFunc { get; set; } public Func> RemoveStockAsyncFunc { get; set; } public Task AddStockAsync(InventoryItemId itemId, int quantity) { return this.AddStockAsyncFunc(itemId, quantity); } public Task CreateInventoryItemAsync(InventoryItem item) { return this.CreateInventoryItemAsyncFunc(item); } public Task> GetCustomerInventoryAsync() { return this.GetCustomerInventoryAsyncFunc(); } public Task> GetCustomerInventoryAsync(CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task IsItemInInventoryAsync(InventoryItemId itemId) { return this.IsItemInInventoryAsyncFunc(itemId); } public Task IsItemInInventoryAsync(InventoryItemId itemId, CancellationToken cancellationToken) { return this.IsItemInInventoryAsyncFunc(itemId); } public Task RemoveStockAsync(InventoryItemId itemId, int quantity, CustomerOrderActorMessageId amId) { return this.RemoveStockAsyncFunc(itemId, quantity, amId); } } } ================================================ FILE: ReferenceApp/Mocks/MockReliableDictionary.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Data.Notifications; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class MockReliableDictionary : IReliableDictionary where TKey : IComparable, IEquatable { private ConcurrentDictionary dictionary = new ConcurrentDictionary(); public event EventHandler> DictionaryChanged; public Uri Name { get; set; } public Func, NotifyDictionaryRebuildEventArgs, Task> RebuildNotificationAsyncCallback { set { throw new NotImplementedException(); } } public Task AddAsync(ITransaction tx, TKey key, TValue value) { if (!this.dictionary.TryAdd(key, value)) { throw new InvalidOperationException("key already exists: " + key.ToString()); } return Task.FromResult(true); } public Task AddAsync(ITransaction tx, TKey key, TValue value, TimeSpan timeout, CancellationToken cancellationToken) { if (!this.dictionary.TryAdd(key, value)) { throw new InvalidOperationException("key already exists: " + key.ToString()); } return Task.FromResult(true); } public Task AddOrUpdateAsync(ITransaction tx, TKey key, Func addValueFactory, Func updateValueFactory) { return Task.FromResult(this.dictionary.AddOrUpdate(key, addValueFactory, updateValueFactory)); } public Task AddOrUpdateAsync(ITransaction tx, TKey key, TValue addValue, Func updateValueFactory) { return Task.FromResult(this.dictionary.AddOrUpdate(key, addValue, updateValueFactory)); } public Task AddOrUpdateAsync( ITransaction tx, TKey key, Func addValueFactory, Func updateValueFactory, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.AddOrUpdate(key, addValueFactory, updateValueFactory)); } public Task AddOrUpdateAsync( ITransaction tx, TKey key, TValue addValue, Func updateValueFactory, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.AddOrUpdate(key, addValue, updateValueFactory)); } public Task ClearAsync() { this.dictionary.Clear(); return Task.FromResult(true); } public Task ClearAsync(TimeSpan timeout, CancellationToken cancellationToken) { this.dictionary.Clear(); return Task.FromResult(true); } public Task ContainsKeyAsync(ITransaction tx, TKey key) { return Task.FromResult(this.dictionary.ContainsKey(key)); } public Task ContainsKeyAsync(ITransaction tx, TKey key, LockMode lockMode) { return Task.FromResult(this.dictionary.ContainsKey(key)); } public Task ContainsKeyAsync(ITransaction tx, TKey key, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.ContainsKey(key)); } public Task ContainsKeyAsync(ITransaction tx, TKey key, LockMode lockMode, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.ContainsKey(key)); } public Task> TryGetValueAsync(ITransaction tx, TKey key) { TValue value; bool result = this.dictionary.TryGetValue(key, out value); return Task.FromResult(new ConditionalValue(result, value)); } public Task> TryGetValueAsync(ITransaction tx, TKey key, LockMode lockMode) { TValue value; bool result = this.dictionary.TryGetValue(key, out value); return Task.FromResult(new ConditionalValue(result, value)); } public Task> TryGetValueAsync(ITransaction tx, TKey key, TimeSpan timeout, CancellationToken cancellationToken) { TValue value; bool result = this.dictionary.TryGetValue(key, out value); return Task.FromResult(new ConditionalValue(result, value)); } public Task> TryGetValueAsync( ITransaction tx, TKey key, LockMode lockMode, TimeSpan timeout, CancellationToken cancellationToken) { TValue value; bool result = this.dictionary.TryGetValue(key, out value); return Task.FromResult(new ConditionalValue(result, value)); } public Task SetAsync(ITransaction tx, TKey key, TValue value) { this.dictionary[key] = value; return Task.FromResult(true); } public Task SetAsync(ITransaction tx, TKey key, TValue value, TimeSpan timeout, CancellationToken cancellationToken) { this.dictionary[key] = value; return Task.FromResult(true); } public Task GetOrAddAsync(ITransaction tx, TKey key, Func valueFactory) { return Task.FromResult(this.dictionary.GetOrAdd(key, valueFactory)); } public Task GetOrAddAsync(ITransaction tx, TKey key, TValue value) { return Task.FromResult(this.dictionary.GetOrAdd(key, value)); } public Task GetOrAddAsync(ITransaction tx, TKey key, Func valueFactory, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.GetOrAdd(key, valueFactory)); } public Task GetOrAddAsync(ITransaction tx, TKey key, TValue value, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.GetOrAdd(key, value)); } public Task TryAddAsync(ITransaction tx, TKey key, TValue value) { return Task.FromResult(this.dictionary.TryAdd(key, value)); } public Task TryAddAsync(ITransaction tx, TKey key, TValue value, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.TryAdd(key, value)); } public Task> TryRemoveAsync(ITransaction tx, TKey key) { TValue outValue; return Task.FromResult(new ConditionalValue(this.dictionary.TryRemove(key, out outValue), outValue)); } public Task> TryRemoveAsync(ITransaction tx, TKey key, TimeSpan timeout, CancellationToken cancellationToken) { return this.TryRemoveAsync(tx, key); } public Task TryUpdateAsync(ITransaction tx, TKey key, TValue newValue, TValue comparisonValue) { return Task.FromResult(this.dictionary.TryUpdate(key, newValue, comparisonValue)); } public Task TryUpdateAsync( ITransaction tx, TKey key, TValue newValue, TValue comparisonValue, TimeSpan timeout, CancellationToken cancellationToken) { return Task.FromResult(this.dictionary.TryUpdate(key, newValue, comparisonValue)); } public Task GetCountAsync() { return Task.FromResult((long)this.dictionary.Count); } public Task>> CreateEnumerableAsync(ITransaction txn) { return Task.FromResult>>(new MockAsyncEnumerable>(this.dictionary)); } public Task>> CreateEnumerableAsync(ITransaction txn, EnumerationMode enumerationMode) { return Task.FromResult>>(new MockAsyncEnumerable>( enumerationMode == EnumerationMode.Unordered ? (IEnumerable>)this.dictionary : this.dictionary.OrderBy(x => x.Key))); } public Task>> CreateEnumerableAsync(ITransaction txn, Func filter, EnumerationMode enumerationMode) { return Task.FromResult>>(new MockAsyncEnumerable>( enumerationMode == EnumerationMode.Unordered ? this.dictionary.Where(x => filter(x.Key)) : this.dictionary.Where(x => filter(x.Key)).OrderBy(x => x.Key))); } public Task GetCountAsync(ITransaction tx) { return Task.FromResult((long)this.dictionary.Count); } } } ================================================ FILE: ReferenceApp/Mocks/MockReliableQueue.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; public class MockReliableQueue : IReliableQueue { private ConcurrentQueue queue = new ConcurrentQueue(); public Task EnqueueAsync(ITransaction tx, T item, TimeSpan timeout, CancellationToken cancellationToken) { this.queue.Enqueue(item); return Task.FromResult(true); } public Task EnqueueAsync(ITransaction tx, T item) { this.queue.Enqueue(item); return Task.FromResult(true); } public Task> TryDequeueAsync(ITransaction tx, TimeSpan timeout, CancellationToken cancellationToken) { T item; bool result = this.queue.TryDequeue(out item); return Task.FromResult((ConditionalValue)Activator.CreateInstance(typeof(ConditionalValue), result, item)); } public Task> TryDequeueAsync(ITransaction tx) { T item; bool result = this.queue.TryDequeue(out item); return Task.FromResult((ConditionalValue)Activator.CreateInstance(typeof(ConditionalValue), result, item)); } public Task> TryPeekAsync(ITransaction tx, LockMode lockMode, TimeSpan timeout, CancellationToken cancellationToken) { T item; bool result = this.queue.TryPeek(out item); return Task.FromResult((ConditionalValue)Activator.CreateInstance(typeof(ConditionalValue), result, item)); } public Task> TryPeekAsync(ITransaction tx, LockMode lockMode) { T item; bool result = this.queue.TryPeek(out item); return Task.FromResult((ConditionalValue)Activator.CreateInstance(typeof(ConditionalValue), result, item)); } public Task> TryPeekAsync(ITransaction tx, TimeSpan timeout, CancellationToken cancellationToken) { T item; bool result = this.queue.TryPeek(out item); return Task.FromResult((ConditionalValue)Activator.CreateInstance(typeof(ConditionalValue), result, item)); } public Task> TryPeekAsync(ITransaction tx) { T item; bool result = this.queue.TryPeek(out item); return Task.FromResult((ConditionalValue)Activator.CreateInstance(typeof(ConditionalValue), result, item)); } public Task ClearAsync() { while (!this.queue.IsEmpty) { T result; this.queue.TryDequeue(out result); } return Task.FromResult(true); } public Task GetCountAsync() { return Task.FromResult((long)this.queue.Count); } public Task> CreateEnumerableAsync(ITransaction tx) { return Task.FromResult>(new MockAsyncEnumerable(this.queue)); } public Task GetCountAsync(ITransaction tx) { return Task.FromResult(this.queue.Count); } public Uri Name { get; set; } } } ================================================ FILE: ReferenceApp/Mocks/MockReliableStateManager.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Data.Notifications; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Fabric; using System.Threading; using System.Threading.Tasks; public class MockReliableStateManager : IReliableStateManagerReplica { private ConcurrentDictionary store = new ConcurrentDictionary(); private Func> datalossFunction; private Dictionary dependencyMap = new Dictionary() { {typeof(IReliableDictionary<,>), typeof(MockReliableDictionary<,>)}, {typeof(IReliableQueue<>), typeof(MockReliableQueue<>)} }; public Func> OnDataLossAsync { set { this.datalossFunction = value; } get { return this.datalossFunction; } } public event EventHandler TransactionChanged; public event EventHandler StateManagerChanged; public Task ClearAsync(ITransaction tx) { this.store.Clear(); return Task.FromResult(true); } public Task ClearAsync() { this.store.Clear(); return Task.FromResult(true); } public ITransaction CreateTransaction() { return new MockTransaction(); } public Task RemoveAsync(string name) { IReliableState result; this.store.TryRemove(this.ToUri(name), out result); return Task.FromResult(true); } public Task RemoveAsync(ITransaction tx, string name) { IReliableState result; this.store.TryRemove(this.ToUri(name), out result); return Task.FromResult(true); } public Task RemoveAsync(string name, TimeSpan timeout) { IReliableState result; this.store.TryRemove(this.ToUri(name), out result); return Task.FromResult(true); } public Task RemoveAsync(ITransaction tx, string name, TimeSpan timeout) { IReliableState result; this.store.TryRemove(this.ToUri(name), out result); return Task.FromResult(true); } public Task RemoveAsync(Uri name) { IReliableState result; this.store.TryRemove(name, out result); return Task.FromResult(true); } public Task RemoveAsync(Uri name, TimeSpan timeout) { IReliableState result; this.store.TryRemove(name, out result); return Task.FromResult(true); } public Task RemoveAsync(ITransaction tx, Uri name) { IReliableState result; this.store.TryRemove(name, out result); return Task.FromResult(true); } public Task RemoveAsync(ITransaction tx, Uri name, TimeSpan timeout) { IReliableState result; this.store.TryRemove(name, out result); return Task.FromResult(true); } public Task> TryGetAsync(string name) where T : IReliableState { IReliableState item; bool result = this.store.TryGetValue(this.ToUri(name), out item); return Task.FromResult(new ConditionalValue(result, (T)item)); } public Task> TryGetAsync(Uri name) where T : IReliableState { IReliableState item; bool result = this.store.TryGetValue(name, out item); return Task.FromResult(new ConditionalValue(result, (T)item)); } public Task GetOrAddAsync(string name) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(this.ToUri(name), this.GetDependency(typeof(T)))); } public Task GetOrAddAsync(ITransaction tx, string name) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(this.ToUri(name), this.GetDependency(typeof(T)))); } public Task GetOrAddAsync(string name, TimeSpan timeout) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(this.ToUri(name), this.GetDependency(typeof(T)))); } public Task GetOrAddAsync(ITransaction tx, string name, TimeSpan timeout) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(this.ToUri(name), this.GetDependency(typeof(T)))); } public Task GetOrAddAsync(Uri name) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(name, this.GetDependency(typeof(T)))); } public Task GetOrAddAsync(Uri name, TimeSpan timeout) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(name, this.GetDependency(typeof(T)))); } public Task GetOrAddAsync(ITransaction tx, Uri name) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(name, this.GetDependency(typeof(T)))); } public Task GetOrAddAsync(ITransaction tx, Uri name, TimeSpan timeout) where T : IReliableState { return Task.FromResult((T)this.store.GetOrAdd(name, this.GetDependency(typeof(T)))); } public bool TryAddStateSerializer(IStateSerializer stateSerializer) { throw new NotImplementedException(); } private IReliableState GetDependency(Type t) { Type mockType = this.dependencyMap[t.GetGenericTypeDefinition()]; return (IReliableState)Activator.CreateInstance(mockType.MakeGenericType(t.GetGenericArguments())); } private Uri ToUri(string name) { return new Uri("mock://" + name, UriKind.Absolute); } public IAsyncEnumerator GetAsyncEnumerator() { return new MockAsyncEnumerator(this.store.Values.GetEnumerator()); } public void Initialize(StatefulServiceInitializationParameters initializationParameters) { } public Task OpenAsync(ReplicaOpenMode openMode, IStatefulServicePartition partition, CancellationToken cancellationToken) { return null; } public Task ChangeRoleAsync(ReplicaRole newRole, CancellationToken cancellationToken) { return Task.FromResult(true); } public Task CloseAsync(CancellationToken cancellationToken) { return Task.FromResult(true); } public void Abort() { } public Task BackupAsync(Func> backupCallback) { throw new NotImplementedException(); } public Task BackupAsync(BackupOption option, TimeSpan timeout, CancellationToken cancellationToken, Func> backupCallback) { throw new NotImplementedException(); } public Task RestoreAsync(string backupFolderPath) { throw new NotImplementedException(); } public Task RestoreAsync(string backupFolderPath, RestorePolicy restorePolicy, CancellationToken cancellationToken) { throw new NotImplementedException(); } } } ================================================ FILE: ReferenceApp/Mocks/MockServiceProxy.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Communication.Client; using Microsoft.ServiceFabric.Services.Remoting; using Microsoft.ServiceFabric.Services.Remoting.Client; using System; using System.Collections.Generic; public class MockServiceProxy : IServiceProxy { private IDictionary> createFunctions = new Dictionary>(); public Type ServiceInterfaceType { get; private set; } public IServiceRemotingPartitionClient ServicePartitionClient { get; private set; } public TServiceInterface Create(Uri serviceName) where TServiceInterface : IService { this.ServiceInterfaceType = typeof(TServiceInterface); return (TServiceInterface)this.createFunctions[typeof(TServiceInterface)](serviceName); } //public TServiceInterface Create(Uri serviceName, ServicePartitionKey key) where TServiceInterface : IService //{ // return (TServiceInterface)this.createFunctions[typeof(TServiceInterface)](serviceName); //} public TServiceInterface Create(Uri serviceUri, ServicePartitionKey partitionKey = null, TargetReplicaSelector targetReplicaSelector = TargetReplicaSelector.Default, string listenerName = null) where TServiceInterface : IService { return (TServiceInterface)this.createFunctions[typeof(TServiceInterface)](serviceUri); } public void Supports(Func Create) { this.createFunctions[typeof(TServiceInterface)] = Create; } } } ================================================ FILE: ReferenceApp/Mocks/MockServiceProxyFactory.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using System; using Microsoft.ServiceFabric.Services.Remoting; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Communication.Client; using System.Collections.Concurrent; /// /// Wrapper class for the static ServiceProxy. /// public class MockServiceProxyFactory : IServiceProxyFactory { private ConcurrentDictionary mockServiceLookupTable = new ConcurrentDictionary(); public TServiceInterface CreateServiceProxy(Uri serviceUri, ServicePartitionKey partitionKey = null, TargetReplicaSelector targetReplicaSelector = TargetReplicaSelector.Default, string listenerName = null) where TServiceInterface : IService { MockServiceProxy serviceProxy = new MockServiceProxy(); serviceProxy.Supports((mockUri) => mockServiceLookupTable[serviceUri]); return serviceProxy.Create(serviceUri, partitionKey, targetReplicaSelector, listenerName); } public void AssociateMockServiceAndName(Uri mockServiceUri, IService mockService) { mockServiceLookupTable.AddOrUpdate(mockServiceUri, mockService, (uri, service) => mockService); } } } ================================================ FILE: ReferenceApp/Mocks/MockTransaction.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Mocks { using Microsoft.ServiceFabric.Data; using System; using System.Threading.Tasks; public class MockTransaction : ITransaction { public Task CommitAsync() { return Task.FromResult(true); } public void Abort() { } public long TransactionId { get { return 0L; } } public long CommitSequenceNumber { get { throw new NotImplementedException(); } } public void Dispose() { } public Task GetVisibilitySequenceNumberAsync() { return Task.FromResult(0L); } } } ================================================ FILE: ReferenceApp/Mocks/Mocks.csproj ================================================  Debug AnyCPU {00E00484-BD00-40CD-B2CC-1CFA8E893972} Library Properties Mocks Mocks v4.5.2 512 true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {1e7e813f-43d3-4d0b-8546-5e1023873f28} CustomerOrder.Domain {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain {a44fc2c5-6781-447e-80f5-7265b960b36a} RestockRequest.Domain {4162f266-d657-4143-aa62-626c10d23561} RestockRequestManager.Domain This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/Mocks/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Mocks")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Mocks")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("00e00484-bd00-40cd-b2cc-1cfa8e893972")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/Mocks/app.config ================================================  ================================================ FILE: ReferenceApp/Mocks/packages.config ================================================  ================================================ FILE: ReferenceApp/Nuget.Config ================================================  ================================================ FILE: ReferenceApp/RestockRequest.Actor/ActorEventSource.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Actor { using System; using System.Diagnostics.Tracing; using System.Threading.Tasks; using Microsoft.ServiceFabric.Actors.Runtime; [EventSource(Name = "MyCompany-Web_UIApplication-RestockRequestActor")] internal sealed class ActorEventSource : EventSource { private const int MessageEventId = 1; // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. private const int ActorMessageEventId = 2; private const int ActorHostInitializationFailedEventId = 3; public static readonly ActorEventSource Current = new ActorEventSource(); static ActorEventSource() { // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. // This problem will be fixed in .NET Framework 4.6.2. Task.Run(() => { }).Wait(); } // Instance constructor is private to enforce singleton semantics private ActorEventSource() : base() { } // Define an instance method for each event you want to record and apply an [Event] attribute to it. // The method name is the name of the event. // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). // Put [NonEvent] attribute on all methods that do not define an event. // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx [NonEvent] public void Message(string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); this.Message(finalMessage); } } [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] public void Message(string message) { if (this.IsEnabled()) { this.WriteEvent(MessageEventId, message); } } [NonEvent] public void ActorMessage(Actor actor, string message, params object[] args) { if (this.IsEnabled() && actor.Id != null && actor.ActorService != null && actor.ActorService.Context != null && actor.ActorService.Context.CodePackageActivationContext != null) { string finalMessage = string.Format(message, args); this.ActorMessage( actor.GetType().ToString(), actor.Id.ToString(), actor.ActorService.Context.CodePackageActivationContext.ApplicationTypeName, actor.ActorService.Context.CodePackageActivationContext.ApplicationName, actor.ActorService.Context.ServiceTypeName, actor.ActorService.Context.ServiceName.ToString(), actor.ActorService.Context.PartitionId, actor.ActorService.Context.ReplicaId, actor.ActorService.Context.NodeContext.NodeName, finalMessage); } } [Event(ActorHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Actor host initialization failed", Keywords = Keywords.HostInitialization)] public void ActorHostInitializationFailed(string exception) { this.WriteEvent(ActorHostInitializationFailedEventId, exception); } [Event(ActorMessageEventId, Level = EventLevel.Informational, Message = "{9}")] private void ActorMessage( string actorType, string actorId, string applicationTypeName, string applicationName, string serviceTypeName, string serviceName, Guid partitionId, long replicaOrInstanceId, string nodeName, string message) { this.WriteEvent( ActorMessageEventId, actorType, actorId, applicationTypeName, applicationName, serviceTypeName, serviceName, partitionId, replicaOrInstanceId, nodeName, message); } // Event keywords can be used to categorize events. // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. public static class Keywords { public const EventKeywords HostInitialization = (EventKeywords) 0x1L; } } } ================================================ FILE: ReferenceApp/RestockRequest.Actor/App.config ================================================  ================================================ FILE: ReferenceApp/RestockRequest.Actor/PackageRoot/Config/Settings.xml ================================================ 
================================================ FILE: ReferenceApp/RestockRequest.Actor/PackageRoot/ServiceManifest.xml ================================================  RestockRequest.Actor.exe ================================================ FILE: ReferenceApp/RestockRequest.Actor/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("RestockRequestActor")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RestockRequestActor")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("4c5acf3b-e6d1-4fbd-8b23-a9fa7ba6326e")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/RestockRequest.Actor/RestockRequest.Actor.csproj ================================================  Debug x64 {4C5ACF3B-E6D1-4FBD-8B23-A9FA7BA6326E} Exe Properties RestockRequest.Actor RestockRequest.Actor v4.5.2 512 true True true PackageRoot $(MSBuildProjectName) x64 true full false bin\Debug\ DEBUG;TRACE prompt 4 x64 pdbonly true bin\Release\ TRACE prompt 4 ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True Designer {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {A44FC2C5-6781-447E-80F5-7265B960B36A} RestockRequest.Domain This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/RestockRequest.Actor/RestockRequestActor.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Actor { using System; using System.Fabric; using System.Threading.Tasks; using Microsoft.ServiceFabric.Actors.Runtime; using Microsoft.ServiceFabric.Data; using RestockRequest.Domain; using Microsoft.ServiceFabric.Actors; //internal class RestockRequestActor : StatefulActor, IRestockRequestActor, IRemindable internal class RestockRequestActor : Actor, IRestockRequestActor, IRemindable { // The duration the verification at beginning of each pipeline step takes private static TimeSpan PipelineStageVerificationDelay = TimeSpan.FromSeconds(5); // The duration each step of the pipeline takes private static TimeSpan PipelineStageProcessingDuration = TimeSpan.FromSeconds(10); private static string ActorStatePropertyName = "RestockRequestActorStatePropertyName"; public RestockRequestActor(ActorService actorService, ActorId actorId) : base (actorService, actorId) { } public Task ReceiveReminderAsync(string reminderName, byte[] context, TimeSpan dueTime, TimeSpan period) { switch (reminderName) { case RestockRequestReminderNames.RestockPipelineChangeReminderName: return this.RestockPipeline(); default: // We should never arrive here normally. The system won't call reminders that don't exist. // But for our own sake in case we add a new reminder somewhere and forget to handle it, this will remind us. throw new InvalidOperationException("Unknown reminder: " + reminderName); } } /// /// Accepts a restock request and changes the Actor's state accordingly. The request is processed /// async and the caller will be notified when the processing is done. /// /// /// public async Task AddRestockRequestAsync(RestockRequest request) { RestockRequestActorState state = await this.StateManager.GetStateAsync(ActorStatePropertyName); if (state.IsStarted()) //Don't accept a request that is already started { ActorEventSource.Current.Message(string.Format("RestockRequestActor: {0}: Can't accept restock request in this state", state)); throw new InvalidOperationException(string.Format("{0}: Can't accept restock request in this state", state)); } // Accept the request ActorEventSource.Current.ActorMessage(this, "RestockRequestActor: Accept update quantity request {0}", request); state.Status = RestockRequestStatus.Accepted; state.Request = request; await this.StateManager.SetStateAsync(ActorStatePropertyName, state); // Start a reminder to go through the processing pipeline. // A reminder keeps the actor from being garbage collected due to lack of use, // which works better than a timer in this case. await this.RegisterReminderAsync( RestockRequestReminderNames.RestockPipelineChangeReminderName, null, PipelineStageVerificationDelay, PipelineStageProcessingDuration); return; } protected override async Task OnActivateAsync() { ConditionalValue state = await this.StateManager.TryGetStateAsync(ActorStatePropertyName); if (!state.HasValue) { await this.StateManager.SetStateAsync(ActorStatePropertyName, new RestockRequestActorState()); ActorEventSource.Current.ActorMessage(this, "RestockRequestActor: State initialized"); } return; } /// /// Simulates the processing of a restock request by advancing the processing status each time this method is invoked /// until it reaches the complete stage. /// /// internal async Task RestockPipeline() { RestockRequestActorState state = await this.StateManager.GetStateAsync(ActorStatePropertyName); ActorEventSource.Current.ActorMessage(this, "RestockRequestActor: {0}: Pipeline change reminder", state); switch (state.Status) { case RestockRequestStatus.Accepted: // Change to next step and let it "execute" until the reminder fires again state.Status = RestockRequestStatus.Manufacturing; break; case RestockRequestStatus.Manufacturing: // Changet the step to completed to indicate the "processing" is complete. state.Status = RestockRequestStatus.Completed; // Raise the event to let interested parties (RestockRequestManager) know that the restock is complete this.SignalRequestStatusChange(state); // Done, so unregister the reminder await this.UnregisterRestockPipelineChangeReminderAsync(); break; default: throw new InvalidOperationException(string.Format("{0}: remainder received in invalid status", state)); } await this.StateManager.SetStateAsync(ActorStatePropertyName, state); return; } private void SignalRequestStatusChange(RestockRequestActorState state) { ActorEventSource.Current.ActorMessage(this, "RestockRequestActor: {0}: Raise event for state change", state); IRestockRequestEvents events = this.GetEvent(); events.RestockRequestCompleted(this.Id, state.Request); } private Task UnregisterRestockPipelineChangeReminderAsync() { IActorReminder reminder; try { reminder = this.GetReminder(RestockRequestReminderNames.RestockPipelineChangeReminderName); } catch (FabricException) { reminder = null; } return (reminder == null) ? Task.FromResult(true) : this.UnregisterReminderAsync(reminder); } } } ================================================ FILE: ReferenceApp/RestockRequest.Actor/RestockRequestActorState.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Actor { using System; using System.Runtime.Serialization; using RestockRequest.Domain; [DataContract] internal sealed class RestockRequestActorState { [DataMember] public RestockRequest Request { get; set; } [DataMember] public RestockRequestStatus Status { get; set; } public bool IsStarted() { return this.Status == RestockRequestStatus.Manufacturing || this.Status == RestockRequestStatus.Accepted; } public override string ToString() { if (this.Request == null) { return String.Format("{0}", this.Status); } return string.Format("{0}: {1}", this.Request, this.Status); } } } ================================================ FILE: ReferenceApp/RestockRequest.Actor/RestockRequestReminderNames.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Actor { internal static class RestockRequestReminderNames { public const string RestockPipelineChangeReminderName = "RestockPipelineChange"; } } ================================================ FILE: ReferenceApp/RestockRequest.Actor/ServiceHost.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Actor { using System; using System.Threading; using Microsoft.ServiceFabric.Actors.Runtime; public class ServiceHost { public static void Main(string[] args) { try { ActorRuntime.RegisterActorAsync().GetAwaiter().GetResult(); Thread.Sleep(Timeout.Infinite); } catch (Exception e) { ActorEventSource.Current.ActorHostInitializationFailed(e.ToString()); throw; } } } } ================================================ FILE: ReferenceApp/RestockRequest.Actor/packages.config ================================================  ================================================ FILE: ReferenceApp/RestockRequest.Domain/IRestockRequestActor.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Domain { using System.Threading.Tasks; using Microsoft.ServiceFabric.Actors; public interface IRestockRequestActor : IActor, IActorEventPublisher { Task AddRestockRequestAsync(RestockRequest request); } } ================================================ FILE: ReferenceApp/RestockRequest.Domain/IRestockRequestEvents.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Domain { using Microsoft.ServiceFabric.Actors; public interface IRestockRequestEvents : IActorEvents { // Notify that the actor idenfitied by actor id has completed the request. // The recipient can find the actor id based on the request item id, but we want to avoid another lookup void RestockRequestCompleted(ActorId actorId, RestockRequest request); } } ================================================ FILE: ReferenceApp/RestockRequest.Domain/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("RestockRequestActor.Interfaces")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RestockRequestActor.Interfaces")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("a44fc2c5-6781-447e-80f5-7265b960b36a")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/RestockRequest.Domain/RestockRequest.Domain.csproj ================================================  Debug x64 {A44FC2C5-6781-447E-80F5-7265B960B36A} Library Properties RestockRequest.Domain RestockRequest.Domain v4.5.2 512 true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/RestockRequest.Domain/RestockRequest.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Domain { using System; using System.Runtime.Serialization; using Inventory.Domain; [DataContract] public sealed class RestockRequest { public RestockRequest(InventoryItemId itemId, int quantity) { this.ItemId = itemId; this.Quantity = quantity; } [DataMember] public InventoryItemId ItemId { get; private set; } [DataMember] public int Quantity { get; private set; } public override string ToString() { return String.Format("ItemId: {0}, Quantity: {1}", this.ItemId, this.Quantity); } } } ================================================ FILE: ReferenceApp/RestockRequest.Domain/RestockRequestStatus.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequest.Domain { public enum RestockRequestStatus { NA = 0, Accepted, Manufacturing, Completed, } } ================================================ FILE: ReferenceApp/RestockRequest.Domain/app.config ================================================  ================================================ FILE: ReferenceApp/RestockRequest.Domain/packages.config ================================================  ================================================ FILE: ReferenceApp/RestockRequestManager.Domain/IRestockRequestManager.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequestManager.Domain { using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Remoting; using RestockRequest.Domain; public interface IRestockRequestManager : IService { Task AddRestockRequestAsync(RestockRequest request); } } ================================================ FILE: ReferenceApp/RestockRequestManager.Domain/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("RestockRequestManager.Domain")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RestockRequestManager.Domain")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("4162f266-d657-4143-aa62-626c10d23561")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/RestockRequestManager.Domain/RestockRequestManager.Domain.csproj ================================================  Debug x64 {4162F266-D657-4143-AA62-626C10D23561} Library Properties RestockRequestManager.Domain RestockRequestManager.Domain v4.5.2 512 true bin\x64\Debug\ DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset bin\x64\Release\ TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True {a44fc2c5-6781-447e-80f5-7265b960b36a} RestockRequest.Domain This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/RestockRequestManager.Domain/app.config ================================================  ================================================ FILE: ReferenceApp/RestockRequestManager.Domain/packages.config ================================================  ================================================ FILE: ReferenceApp/RestockRequestManager.Service/App.config ================================================  ================================================ FILE: ReferenceApp/RestockRequestManager.Service/PackageRoot/Config/Settings.xml ================================================ 
================================================ FILE: ReferenceApp/RestockRequestManager.Service/PackageRoot/ServiceManifest.xml ================================================  RestockRequestManager.Service.exe ================================================ FILE: ReferenceApp/RestockRequestManager.Service/Program.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequestManager.Service { using System; using System.Threading; using Microsoft.ServiceFabric.Services.Runtime; public class Program { public static void Main(string[] args) { try { ServiceRuntime.RegisterServiceAsync("RestockRequestManagerServiceType", (context) => new RestockRequestManagerService(context)) .GetAwaiter() .GetResult(); Thread.Sleep(Timeout.Infinite); } catch (Exception e) { ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString()); throw; } } } } ================================================ FILE: ReferenceApp/RestockRequestManager.Service/Properties/AssemblyInfo.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("RestockRequestManagerService")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RestockRequestManagerService")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("7c404bc4-7589-488c-ab09-876e5b33b641")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ReferenceApp/RestockRequestManager.Service/RestockRequestManager.Service.csproj ================================================  Debug x64 {7C404BC4-7589-488C-AB09-876E5B33B641} Exe Properties RestockRequestManager.Service RestockRequestManager.Service v4.5.2 512 true True x64 true full false bin\Debug\ DEBUG;TRACE prompt 4 x64 pdbonly true bin\Release\ TRACE prompt 4 $(AdditionalFileItemNames);None ..\packages\Microsoft.ServiceFabric.Actors.2.6.204\lib\net45\Microsoft.ServiceFabric.Actors.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.dll ..\packages\Microsoft.ServiceFabric.Data.2.6.204\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True ..\packages\Microsoft.ServiceFabric.FabricTransport.Internal.2.6.204\lib\net45\Microsoft.ServiceFabric.FabricTransport.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll ..\packages\Microsoft.ServiceFabric.Services.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.dll ..\packages\Microsoft.ServiceFabric.Services.Remoting.2.6.204\lib\net45\Microsoft.ServiceFabric.Services.Remoting.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.dll True ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Management.ServiceModel.XmlSerializers.dll ..\packages\Microsoft.ServiceFabric.5.6.204\lib\net45\System.Fabric.Strings.dll True Designer {9ec0063f-489e-43fe-94b5-bf5f89977cd3} Common {7e9c2dfd-71a5-496d-aa4d-5ec53eaeb9ae} Inventory.Domain {a44fc2c5-6781-447e-80f5-7265b960b36a} RestockRequest.Domain {4162f266-d657-4143-aa62-626c10d23561} RestockRequestManager.Domain This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. ================================================ FILE: ReferenceApp/RestockRequestManager.Service/RestockRequestManagerService.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequestManager.Service { using System; using System.Collections.Generic; using System.Fabric; using System.Threading; using System.Threading.Tasks; using Common; using Inventory.Domain; using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Actors.Client; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; using Microsoft.ServiceFabric.Services.Communication.Runtime; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.ServiceFabric.Services.Remoting.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using RestockRequest.Domain; using RestockRequestManager.Domain; internal class RestockRequestManagerService : StatefulService, IRestockRequestManager, IRestockRequestEvents { //TODO: Look@ use of these variables. private const string ItemIdToActorIdMapName = "actorIdToMapName"; //Name of ItemId-ActorId IReliableDictionary private const string CompletedRequestsQueueName = "completedRequests"; //Name of CompletedRequests IReliableQueue private const string InventoryServiceName = "InventoryService"; private static TimeSpan CompletedRequestsBatchInterval = TimeSpan.FromSeconds(1); private static TimeSpan TxTimeout = TimeSpan.FromSeconds(4); public RestockRequestManagerService(StatefulServiceContext serviceContext) : base(serviceContext) { } public RestockRequestManagerService(StatefulServiceContext serviceContext, IReliableStateManagerReplica reliableStateManagerReplica) : base(serviceContext, reliableStateManagerReplica) { } public string ApplicationName { get { return this.Context.CodePackageActivationContext.ApplicationName; } } /// /// This method uses an IReliableQueue to store completed RestockRequests which are later sent to the client using batch processing. /// We could send the request immediately but we prefer to minimize traffic back to the Inventory Service by batching multiple requests /// in one trip. /// /// /// public async void RestockRequestCompleted(ActorId actorId, RestockRequest request) { IReliableQueue completedRequests = await this.StateManager.GetOrAddAsync>(CompletedRequestsQueueName); using (ITransaction tx = this.StateManager.CreateTransaction()) { await completedRequests.EnqueueAsync(tx, request); await tx.CommitAsync(); } IRestockRequestActor restockRequestActor = ActorProxy.Create(actorId, this.ApplicationName); await restockRequestActor.UnsubscribeAsync(this); //QUESTION:What does this method do? } /// /// This method activates an actor to fulfill the RestockRequest. /// /// /// public async Task AddRestockRequestAsync(RestockRequest request) { try { //Get dictionary of Restock Requests IReliableDictionary requestDictionary = await this.StateManager.GetOrAddAsync>(ItemIdToActorIdMapName); ActorId actorId = ActorId.CreateRandom(); try { using (ITransaction tx = this.StateManager.CreateTransaction()) { await requestDictionary.AddAsync(tx, request.ItemId, actorId); await tx.CommitAsync(); } } catch (ArgumentException) { // restock request already exists return; } // Create actor proxy and send the request IRestockRequestActor restockRequestActor = ActorProxy.Create(actorId, this.ApplicationName); await restockRequestActor.AddRestockRequestAsync(request); // Successfully added, register for event notifications for completion await restockRequestActor.SubscribeAsync(this); ServiceEventSource.Current.ServiceMessage(this, "Created restock request. Item ID: {0}. Actor ID: {1}", request.ItemId, actorId); } catch (InvalidOperationException ex) { ServiceEventSource.Current.Message(string.Format("RestockRequestManagerService: Actor rejected {0}: {1}", request, ex)); throw; } catch (Exception ex) { ServiceEventSource.Current.Message(string.Format("RestockRequestManagerService: Exception {0}: {1}", request, ex)); throw; } } protected override IEnumerable CreateServiceReplicaListeners() { return new[] { new ServiceReplicaListener(context => this.CreateServiceRemotingListener(context)) }; } /// /// Drains the queue of completed restock requests sends them to InventoryService. /// /// /// protected override async Task RunAsync(CancellationToken cancellationToken) { IReliableQueue completedRequests = await this.StateManager.GetOrAddAsync>(CompletedRequestsQueueName); while (!cancellationToken.IsCancellationRequested) { using (ITransaction tx = this.StateManager.CreateTransaction()) { ConditionalValue result = await completedRequests.TryDequeueAsync(tx, TxTimeout, cancellationToken); if (result.HasValue) { ServiceUriBuilder builder = new ServiceUriBuilder(InventoryServiceName); IInventoryService inventoryService = ServiceProxy.Create(builder.ToUri(), result.Value.ItemId.GetPartitionKey()); await inventoryService.AddStockAsync(result.Value.ItemId, result.Value.Quantity); ServiceEventSource.Current.ServiceMessage( this, "Adding stock to inventory service. ID: {0}. Quantity: {1}", result.Value.ItemId, result.Value.Quantity); } // This commits the dequeue operations. // If the request to add the stock to the inventory service throws, this commit will not execute // and the items will remain on the queue, so we can be sure that we didn't dequeue items // that didn't get saved successfully in the inventory service. // However there is a very small chance that the stock was added to the inventory service successfully, // but service execution stopped before reaching this commit (machine crash, for example). await tx.CommitAsync(); } await Task.Delay(CompletedRequestsBatchInterval, cancellationToken); } } } } ================================================ FILE: ReferenceApp/RestockRequestManager.Service/ServiceEventSource.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace RestockRequestManager.Service { using System; using System.Diagnostics.Tracing; using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Runtime; [EventSource(Name = "MyCompany-Web_UIApplication-RestockRequestManagerService")] internal sealed class ServiceEventSource : EventSource { private const int MessageEventId = 1; // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. private const int ServiceMessageEventId = 2; private const int ServiceTypeRegisteredEventId = 3; private const int ServiceHostInitializationFailedEventId = 4; // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity. // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities, // and other statistics. private const int ServiceRequestStartEventId = 5; private const int ServiceRequestStopEventId = 6; private const int ServiceRequestFailedEventId = 7; public static readonly ServiceEventSource Current = new ServiceEventSource(); static ServiceEventSource() { // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. // This problem will be fixed in .NET Framework 4.6.2. Task.Run(() => { }).Wait(); } // Instance constructor is private to enforce singleton semantics private ServiceEventSource() : base() { } // Define an instance method for each event you want to record and apply an [Event] attribute to it. // The method name is the name of the event. // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). // Put [NonEvent] attribute on all methods that do not define an event. // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx [NonEvent] public void Message(string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); this.Message(finalMessage); } } [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] public void Message(string message) { if (this.IsEnabled()) { this.WriteEvent(MessageEventId, message); } } [NonEvent] public void ServiceMessage(StatefulService service, string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); this.ServiceMessage( service.Context.ServiceName.ToString(), service.Context.ServiceTypeName, service.Context.ReplicaId, service.Context.PartitionId, service.Context.CodePackageActivationContext.ApplicationName, service.Context.CodePackageActivationContext.ApplicationTypeName, service.Context.NodeContext.NodeName, finalMessage); } } [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)] public void ServiceTypeRegistered(int hostProcessId, string serviceType) { this.WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType); } [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)] public void ServiceHostInitializationFailed(string exception) { this.WriteEvent(ServiceHostInitializationFailedEventId, exception); } [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)] public void ServiceRequestStart(string requestTypeName) { this.WriteEvent(ServiceRequestStartEventId, requestTypeName); } [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)] public void ServiceRequestStop(string requestTypeName) { this.WriteEvent(ServiceRequestStopEventId, requestTypeName); } [Event(ServiceRequestFailedEventId, Level = EventLevel.Error, Message = "Service request '{0}' failed", Keywords = Keywords.Requests)] public void ServiceRequestFailed(string requestTypeName, string exception) { this.WriteEvent(ServiceRequestFailedEventId, exception); } [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")] private void ServiceMessage( string serviceName, string serviceTypeName, long replicaOrInstanceId, Guid partitionId, string applicationName, string applicationTypeName, string nodeName, string message) { this.WriteEvent( ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message); } // Event keywords can be used to categorize events. // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. public static class Keywords { public const EventKeywords Requests = (EventKeywords) 0x1L; public const EventKeywords ServiceInitialization = (EventKeywords) 0x2L; } } } ================================================ FILE: ReferenceApp/RestockRequestManager.Service/packages.config ================================================  ================================================ FILE: ReferenceApp/Web.Service/.bowerrc ================================================ { "directory": "wwwroot/lib" } ================================================ FILE: ReferenceApp/Web.Service/App.config ================================================  ================================================ FILE: ReferenceApp/Web.Service/Controllers/HomeController.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; namespace Web.Service.Controllers { public class HomeController : Controller { public IActionResult Index() { return View(); } public IActionResult Admin() { return View(); } public IActionResult OrderConfirmation() { return View(); } public IActionResult Error() { return View(); } } } ================================================ FILE: ReferenceApp/Web.Service/Controllers/InventoryController.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Web.Service.Controllers { using System; using System.Threading.Tasks; using Common; using Inventory.Domain; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.AspNetCore.Mvc; public class InventoryController : Controller { private const string InventoryServiceName = "InventoryService"; /// /// Calls and adds a new item to inventory. /// /// ///Description ///Price ///Number ///Reorder Threshold ///Max /// String [HttpPost] [Route("api/inventory/add/{description}/{price}/{number}/{reorderThreshold}/{max}")] public Task CreateInventoryItem(string description, decimal price, int number, int reorderThreshold, int max) { InventoryItem i = new InventoryItem(description, price, number, reorderThreshold, max); ServiceUriBuilder builder = new ServiceUriBuilder(InventoryServiceName); IInventoryService inventoryServiceClient = ServiceProxy.Create(builder.ToUri(), i.Id.GetPartitionKey()); try { return inventoryServiceClient.CreateInventoryItemAsync(i); } catch (Exception ex) { ServiceEventSource.Current.Message("Web Service: Exception creating {0}: {1}", i, ex); throw; } } } } ================================================ FILE: ReferenceApp/Web.Service/Controllers/OrdersController.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Web.Service.Controllers { using System; using System.Collections.Generic; using System.Threading.Tasks; using Common; using CustomerOrder.Domain; using Microsoft.ServiceFabric.Actors; using Microsoft.ServiceFabric.Actors.Client; using Microsoft.AspNetCore.Mvc; public class OrdersController : Controller { private const string CustomerOrderServiceName = "CustomerOrderActorService"; /// /// POST api/orders /// Based on a shopping cart passed into the method, PostCheckout creates an actor proxy object to activate an actor instance of CustomerOrderActor, /// which is used to represent the state of the customer order. Through the actor proxy, the FulfillOrderAsync method is invoked on the actor /// to fulfill the customer order by removing items from inventory. /// /// In the current version of this example, the shopping cart which a customer uses to check out exists /// entirely on the client side. A shopping cart, in this example, is therefore stateless and its state is /// only committed to memory when a customer order is created and an Actor Id is associated with it. /// /// Because the status of an order is changed inside the FulfillOrderAsync method, the OrdersController relies /// on a separate GetStatus method that the client can call to see if the Status of the order has changed to completed. /// There is currently no event notification to the WebUI frontend if an order completes. /// /// /// /// Guid to identify the order and allow for status look-up later. [HttpPost] [Route("api/orders")] public async Task PostCheckout(List cart) { ServiceEventSource.Current.Message("Now printing cart for POSTCHECKOUT..."); foreach (CustomerOrderItem item in cart) { ServiceEventSource.Current.Message("Guid {0}, quantity {1}", item.ItemId.ToString(), item.Quantity.ToString()); } Guid orderId = Guid.NewGuid(); ServiceUriBuilder builder = new ServiceUriBuilder(CustomerOrderServiceName); //We create a unique Guid that is associated with a customer order, as well as with the actor that represents that order's state. ICustomerOrderActor customerOrder = ActorProxy.Create(new ActorId(orderId), builder.ToUri()); try { await customerOrder.SubmitOrderAsync(cart); ServiceEventSource.Current.Message("Customer order submitted successfully. ActorOrderID: {0} created", orderId); } catch (InvalidOperationException ex) { ServiceEventSource.Current.Message("Web Service: Actor rejected {0}: {1}", customerOrder, ex); throw; } catch (Exception ex) { ServiceEventSource.Current.Message("Web Service: Exception {0}: {1}", customerOrder, ex); throw; } return orderId; } /// /// Looks up a customer order based on its Guid identifier and by using an ActorProxy, retrieves the order's status and returns it to the client. /// /// /// String [HttpGet] [Route("api/orders/{customerOrderId}")] public Task GetOrderStatus(Guid customerOrderId) { ServiceUriBuilder builder = new ServiceUriBuilder(CustomerOrderServiceName); ICustomerOrderActor customerOrder = ActorProxy.Create(new ActorId(customerOrderId), builder.ToUri()); try { return customerOrder.GetOrderStatusAsStringAsync(); } catch (Exception ex) { ServiceEventSource.Current.Message("Web Service: Exception {0}: {1}", customerOrder, ex); throw; } } } } ================================================ FILE: ReferenceApp/Web.Service/Controllers/StoreController.cs ================================================ // ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. // ------------------------------------------------------------ namespace Web.Service.Controllers { using System; using System.Collections.Generic; using System.Fabric; using System.Fabric.Query; using System.Threading; using System.Threading.Tasks; using Common; using Inventory.Domain; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.AspNetCore.Mvc; public class StoreController : Controller { public const string InventoryServiceName = "InventoryService"; private static FabricClient fc = new FabricClient(); /// /// Right now, this method makes an API call via a ServiceProxy to retrieve Inventory Data directly /// from InventoryService. In the future, this call will be made with a specified category parameter, /// and based on this could call a specific materialized view to return. There would be no option /// to return the entire inventory service in one call, as this would be slow and expensive at scale. /// /// Task of type IEnumerable of InventoryItemView objects [HttpGet] [Route("api/store")] public async Task> GetStore() { ServiceUriBuilder builder = new ServiceUriBuilder(InventoryServiceName); Uri serviceName = builder.ToUri(); List itemList = new List(); ServicePartitionList partitions = await fc.QueryManager.GetPartitionListAsync(serviceName); foreach (Partition p in partitions) { long minKey = (p.PartitionInformation as Int64RangePartitionInformation).LowKey; IInventoryService inventoryServiceClient = ServiceProxy.Create(serviceName, new ServicePartitionKey(minKey)); IEnumerable result = await inventoryServiceClient.GetCustomerInventoryAsync(CancellationToken.None); if (result != null) { itemList.AddRange(result); } } return itemList; } } } ================================================ FILE: ReferenceApp/Web.Service/PackageRoot/Config/Settings.xml ================================================  ================================================ FILE: ReferenceApp/Web.Service/PackageRoot/ServiceManifest.xml ================================================  Web.Service.exe CodePackage ================================================ FILE: ReferenceApp/Web.Service/Program.cs ================================================ using Microsoft.ServiceFabric.Services.Runtime; using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace Web.Service { internal static class Program { /// /// This is the entry point of the service host process. /// private static void Main() { try { // The ServiceManifest.XML file defines one or more service type names. // Registering a service maps a service type name to a .NET type. // When Service Fabric creates an instance of this service type, // an instance of the class is created in this host process. ServiceRuntime.RegisterServiceAsync("WebServiceType", context => new WebService(context)).GetAwaiter().GetResult(); ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(WebService).Name); // Prevents this host process from terminating so services keeps running. Thread.Sleep(Timeout.Infinite); } catch (Exception e) { ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString()); throw; } } } } ================================================ FILE: ReferenceApp/Web.Service/Properties/launchSettings.json ================================================ { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:1756/", "sslPort": 0 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "Web.Service": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "http://localhost:1757" } } } ================================================ FILE: ReferenceApp/Web.Service/ServiceEventSource.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Fabric; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.ServiceFabric.Services.Runtime; namespace Web.Service { [EventSource(Name = "MyCompany-WebReferenceApplication-Service")] internal sealed class ServiceEventSource : EventSource { public static readonly ServiceEventSource Current = new ServiceEventSource(); static ServiceEventSource() { // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. // This problem will be fixed in .NET Framework 4.6.2. Task.Run(() => { }); } // Instance constructor is private to enforce singleton semantics private ServiceEventSource() : base() { } #region Keywords // Event keywords can be used to categorize events. // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. public static class Keywords { public const EventKeywords Requests = (EventKeywords)0x1L; public const EventKeywords ServiceInitialization = (EventKeywords)0x2L; } #endregion #region Events // Define an instance method for each event you want to record and apply an [Event] attribute to it. // The method name is the name of the event. // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). // Put [NonEvent] attribute on all methods that do not define an event. // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx [NonEvent] public void Message(string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); Message(finalMessage); } } private const int MessageEventId = 1; [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] public void Message(string message) { if (this.IsEnabled()) { WriteEvent(MessageEventId, message); } } [NonEvent] public void ServiceMessage(ServiceContext serviceContext, string message, params object[] args) { if (this.IsEnabled()) { string finalMessage = string.Format(message, args); ServiceMessage( serviceContext.ServiceName.ToString(), serviceContext.ServiceTypeName, GetReplicaOrInstanceId(serviceContext), serviceContext.PartitionId, serviceContext.CodePackageActivationContext.ApplicationName, serviceContext.CodePackageActivationContext.ApplicationTypeName, serviceContext.NodeContext.NodeName, finalMessage); } } // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. private const int ServiceMessageEventId = 2; [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")] private #if UNSAFE unsafe #endif void ServiceMessage( string serviceName, string serviceTypeName, long replicaOrInstanceId, Guid partitionId, string applicationName, string applicationTypeName, string nodeName, string message) { #if !UNSAFE WriteEvent(ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message); #else const int numArgs = 8; fixed (char* pServiceName = serviceName, pServiceTypeName = serviceTypeName, pApplicationName = applicationName, pApplicationTypeName = applicationTypeName, pNodeName = nodeName, pMessage = message) { EventData* eventData = stackalloc EventData[numArgs]; eventData[0] = new EventData { DataPointer = (IntPtr) pServiceName, Size = SizeInBytes(serviceName) }; eventData[1] = new EventData { DataPointer = (IntPtr) pServiceTypeName, Size = SizeInBytes(serviceTypeName) }; eventData[2] = new EventData { DataPointer = (IntPtr) (&replicaOrInstanceId), Size = sizeof(long) }; eventData[3] = new EventData { DataPointer = (IntPtr) (&partitionId), Size = sizeof(Guid) }; eventData[4] = new EventData { DataPointer = (IntPtr) pApplicationName, Size = SizeInBytes(applicationName) }; eventData[5] = new EventData { DataPointer = (IntPtr) pApplicationTypeName, Size = SizeInBytes(applicationTypeName) }; eventData[6] = new EventData { DataPointer = (IntPtr) pNodeName, Size = SizeInBytes(nodeName) }; eventData[7] = new EventData { DataPointer = (IntPtr) pMessage, Size = SizeInBytes(message) }; WriteEventCore(ServiceMessageEventId, numArgs, eventData); } #endif } private const int ServiceTypeRegisteredEventId = 3; [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)] public void ServiceTypeRegistered(int hostProcessId, string serviceType) { WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType); } private const int ServiceHostInitializationFailedEventId = 4; [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)] public void ServiceHostInitializationFailed(string exception) { WriteEvent(ServiceHostInitializationFailedEventId, exception); } // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity. // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities, // and other statistics. private const int ServiceRequestStartEventId = 5; [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)] public void ServiceRequestStart(string requestTypeName) { WriteEvent(ServiceRequestStartEventId, requestTypeName); } private const int ServiceRequestStopEventId = 6; [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)] public void ServiceRequestStop(string requestTypeName, string exception = "") { WriteEvent(ServiceRequestStopEventId, requestTypeName, exception); } #endregion #region Private methods private static long GetReplicaOrInstanceId(ServiceContext context) { StatelessServiceContext stateless = context as StatelessServiceContext; if (stateless != null) { return stateless.InstanceId; } StatefulServiceContext stateful = context as StatefulServiceContext; if (stateful != null) { return stateful.ReplicaId; } throw new NotSupportedException("Context type not supported."); } #if UNSAFE private int SizeInBytes(string s) { if (s == null) { return 0; } else { return (s.Length + 1) * sizeof(char); } } #endif #endregion } } ================================================ FILE: ReferenceApp/Web.Service/Startup.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace Web.Service { public class Startup { public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}"); routes.MapRoute( name: "admin", template: "Admin", defaults: new { controller = "Home", action = "Admin" }); routes.MapRoute( name: "orders", template: "OrderConfirmation", defaults: new { controller = "Home", action = "OrderConfirmation" }); }); } } } ================================================ FILE: ReferenceApp/Web.Service/Views/Home/Admin.cshtml ================================================ 

Fabrikam Fashion


Admin Portal!


Description, Price, Number, Reorder Threshold, Max
Bioluminescent Dress, 14.99, 2000, 200, 2000
Electrifying Lightning Skirt, 29.99, 1500, 150, 1500
Blacklight Striped Trousers, 34.99, 3000, 300, 3000

Submission Result = {{createResult}}


================================================ FILE: ReferenceApp/Web.Service/Views/Home/Index.cshtml ================================================ 

Fabrikam Fashion


Item Price Available Quantity
{{row.description}} ${{row.price}} {{row.customerAvailableStock}}


Shopping Cart

Item price Quantity
{{item.description}} ${{item.price}} {{item.quantity}}
Total ${{cart_total}}


================================================ FILE: ReferenceApp/Web.Service/Views/Home/OrderConfirmation.cshtml ================================================ 

Fabrikam Fashion


View Order


{{orderStatus}}



Shopping Cart

Item Price Quantity
{{order.Description}} ${{order.Price}} {{order.Quantity}}
Total ${{completedTotal}}

================================================ FILE: ReferenceApp/Web.Service/Views/Shared/Error.cshtml ================================================ @{ ViewData["Title"] = "Error"; }

Error.

An error occurred while processing your request.

Development Mode

Swapping to Development environment will display more detailed information about the error that occurred.

Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application.

================================================ FILE: ReferenceApp/Web.Service/Views/Shared/_Layout.cshtml ================================================  Fabrikam Fashion @RenderBody(); ================================================ FILE: ReferenceApp/Web.Service/Views/Shared/_ValidationScriptsPartial.cshtml ================================================  ================================================ FILE: ReferenceApp/Web.Service/Views/_ViewImports.cshtml ================================================ @using Web.Service @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers ================================================ FILE: ReferenceApp/Web.Service/Views/_ViewStart.cshtml ================================================ @{ Layout = "_Layout"; } ================================================ FILE: ReferenceApp/Web.Service/Web.Service.csproj ================================================  net452 win7-x64 True bin\Debug\ ================================================ FILE: ReferenceApp/Web.Service/WebService.cs ================================================ using System; using System.Collections.Generic; using System.Fabric; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.ServiceFabric.Services.Communication.AspNetCore; using Microsoft.ServiceFabric.Services.Communication.Runtime; using Microsoft.ServiceFabric.Services.Runtime; namespace Web.Service { /// /// The FabricRuntime creates an instance of this class for each service type instance. /// internal sealed class WebService : StatelessService { public WebService(StatelessServiceContext context) : base(context) { } /// /// Optional override to create listeners (like tcp, http) for this service instance. /// /// The collection of listeners. protected override IEnumerable CreateServiceInstanceListeners() { return new ServiceInstanceListener[] { new ServiceInstanceListener(serviceContext => new WebListenerCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) => { url += "/fabrikam"; ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting WebListener on {url}"); return new WebHostBuilder().UseWebListener() .ConfigureServices( services => services .AddSingleton(serviceContext)) .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup() .UseApplicationInsights() .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None) .UseUrls(url) .Build(); })) }; } } } ================================================ FILE: ReferenceApp/Web.Service/appsettings.Development.json ================================================ { "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Information" } } } ================================================ FILE: ReferenceApp/Web.Service/appsettings.json ================================================ { "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" } } } ================================================ FILE: ReferenceApp/Web.Service/bower.json ================================================ { "name": "asp.net", "private": true, "dependencies": { "bootstrap-css-only": "v3.3.7", "angular": "v1.6.4", "angular-cookies": "v1.6.4" } } ================================================ FILE: ReferenceApp/Web.Service/bundleconfig.json ================================================ // Configure bundling and minification for the project. // More info at https://go.microsoft.com/fwlink/?LinkId=808241 [ { "outputFileName": "wwwroot/css/site.min.css", // An array of relative input file paths. Globbing patterns supported "inputFiles": [ "wwwroot/css/site.css" ] }, { "outputFileName": "wwwroot/js/site.min.js", "inputFiles": [ "wwwroot/js/site.js" ], // Optionally specify minification options "minify": { "enabled": true, "renameLocals": true }, // Optionally generate .map file "sourceMap": false } ] ================================================ FILE: ReferenceApp/Web.Service/wwwroot/css/site.css ================================================ body { padding-top: 50px; padding-bottom: 20px; } /* Wrapping element */ /* Set some basic padding to keep content from hitting the edges */ .body-content { padding-left: 15px; padding-right: 15px; } /* Set widths on the form inputs since otherwise they're 100% wide */ input, select, textarea { max-width: 280px; } /* Carousel */ .carousel-caption p { font-size: 20px; line-height: 1.4; } /* Make .svg files in the carousel display properly in older browsers */ .carousel-inner .item img[src$=".svg"] { width: 100%; } /* Hide/rearrange for smaller screens */ @media screen and (max-width: 767px) { /* Hide captions */ .carousel-caption { display: none; } } ================================================ FILE: ReferenceApp/Web.Service/wwwroot/js/angular-index.js ================================================ (function (angular) { var app = angular.module("fabrikam", ['ngCookies']) .controller("testController", function ($scope, $window, $http, $cookies) { /*--------------------VARIABLES------------------------*/ // Shopping cart for UI display only. description, price, quantity. $scope.cart = []; // ItemId, Quanity. Used in HttpPost to fulfill order. $scope.order = []; $scope.cart_total = 0; // Local variables to keep track of data / aid in formatting for $scope variables. var local_cart = []; var cart_total_unformatted = 0; // Used to keep track of customer's order. Will be undefined until order is placed. $scope.orderCompletedCart = $cookies.getObject('orderPlaced'); $scope.completedTotal = $cookies.get('orderTotal'); /* -----------------------FUNCTIONS---------------------------*/ // Called everytime index.html is loaded. Retrieves inventory items. $scope.initIndex = function () { $http.get('/fabrikam/api/store'). then(function (data) { $scope.inventory = inventory = data.data; }, function (data) { $window.alert("Error retrieving inventory from store."); }); } // Called when a user adds item(s) to cart. $scope.submit = function (row) { // Ensure user enters valid non-negative integer. while (row.quantity != parseInt(row.quantity, 10) || row.quantity <= 0) { row.quantity = ""; row.quantity = prompt("Please enter a non-negative quantity: "); if (row.quantity === null) { $window.alert("Order canceled."); return; } } // Check to see if there are enough items in inventory to order quantity specified. if (row.quantity > row.customerAvailableStock) { $window.alert("Order exceeded available stock."); return; } // Add to shopping cart and calculate total cost. local_cart.push({ 'description': row.description, 'price': row.price, 'quantity': row.quantity }); cart_total_unformatted += row.price * row.quantity; // Update number of available items in inventory. Only updating local copy of inventory, not actual backend data. row.customerAvailableStock -= row.quantity; // Copy data to scope variables to show on webpage. $scope.cart_total = Number(cart_total_unformatted).toFixed(2); $scope.cart = local_cart; // Keep track of id and quantity to send back to order service. $scope.order.push({ 'ItemId': row.id, 'quantity': row.quantity }); // Set UI quantity back to empty. row.quantity = ""; } // Called after user enters email and selects Place Order. // Here's where you would store customer email if you wanted to. $scope.placeOrder = function (customerEmail) { // Make sure to store orders so user can see persisted shopping cart on confirmation page. $cookies.putObject('orderPlaced', local_cart); $cookies.put('orderTotal', $scope.cart_total); // Send data to Order Controller. var promise = $http.post('/fabrikam/api/orders', $scope.order). then(function (response) { // Store returned orderId. //$cookies.put('orderId', response.data); var orderId = response.data; var path = '/fabrikam/OrderConfirmation?orderId='; var address = path.concat(orderId); // Navigate to order confirmation page. window.location.href = address; }, function (response) { $window.alert("Error sending orders."); }); } // Called when orderconfirmation.html is loaded and when user clicks 'Get Order Status' $scope.refreshStatus = function () { // Initialize status in case asynchronous retrieval of status takes a while. $scope.orderStatus = ""; var route = '/fabrikam/api/orders/'; var prodId = $scope.getQueryParameterByName('orderId'); var address = route.concat(prodId); // Retrieve order status based on orderId. $http.get(address). then(function (response) { $scope.orderStatus = orderStatus = response.data; }, function (response) { $window.alert("Error retrieving order status from store."); }); } $scope.createInventory = function () { //description //price //Number //Reorder Threshold //Max var text = $scope.itemsToCreate; var itemArrays = text.split('\n'); for (var i = 0; i < itemArrays.length; i++) { var route = '/fabrikam/api/inventory/add/'; var propertyArray = itemArrays[i].split(','); for (var x = 0; x < propertyArray.length; x++) { var strtemp = encodeURIComponent(propertyArray[x].trim()); strtemp = strtemp.concat("/"); route = route.concat(strtemp) } $http.post(route). then(function (response) { $scope.createResult = createResult = response.data; }, function (response) { $window.alert("Error sending request to Inventory Service."); }); } } $scope.getQueryParameterByName = function (name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search); return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } }); })(angular) ================================================ FILE: ReferenceApp/WebReferenceApp.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26430.6 MinimumVisualStudioVersion = 10.0.40219.1 Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "WebReferenceApplication", "WebReferenceApplication\WebReferenceApplication.sfproj", "{0EE37B65-FCCB-44AE-B4F7-AED85FDEB072}" ProjectSection(ProjectDependencies) = postProject {9EC0063F-489E-43FE-94B5-BF5F89977CD3} = {9EC0063F-489E-43FE-94B5-BF5F89977CD3} {1E7E813F-43D3-4D0B-8546-5E1023873F28} = {1E7E813F-43D3-4D0B-8546-5E1023873F28} {A44FC2C5-6781-447E-80F5-7265B960B36A} = {A44FC2C5-6781-447E-80F5-7265B960B36A} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomerOrder.Actor", "CustomerOrder.Actor\CustomerOrder.Actor.csproj", "{5F0C7805-C91D-47E9-AEDE-946CADEA1C8F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomerOrder.Domain", "CustomerOrder.Domain\CustomerOrder.Domain.csproj", "{1E7E813F-43D3-4D0B-8546-5E1023873F28}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestockRequest.Actor", "RestockRequest.Actor\RestockRequest.Actor.csproj", "{4C5ACF3B-E6D1-4FBD-8B23-A9FA7BA6326E}" ProjectSection(ProjectDependencies) = postProject {9EC0063F-489E-43FE-94B5-BF5F89977CD3} = {9EC0063F-489E-43FE-94B5-BF5F89977CD3} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestockRequest.Domain", "RestockRequest.Domain\RestockRequest.Domain.csproj", "{A44FC2C5-6781-447E-80F5-7265B960B36A}" ProjectSection(ProjectDependencies) = postProject {9EC0063F-489E-43FE-94B5-BF5F89977CD3} = {9EC0063F-489E-43FE-94B5-BF5F89977CD3} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inventory.Service", "Inventory.Service\Inventory.Service.csproj", "{714B1C61-FFA8-4A5E-8DD2-D0A290677293}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestockRequestManager.Service", "RestockRequestManager.Service\RestockRequestManager.Service.csproj", "{7C404BC4-7589-488C-AB09-876E5B33B641}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{9EC0063F-489E-43FE-94B5-BF5F89977CD3}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestockRequestManager.Domain", "RestockRequestManager.Domain\RestockRequestManager.Domain.csproj", "{4162F266-D657-4143-AA62-626C10D23561}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inventory.Domain", "Inventory.Domain\Inventory.Domain.csproj", "{7E9C2DFD-71A5-496D-AA4D-5EC53EAEB9AE}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inventory.UnitTests", "Inventory.UnitTests\Inventory.UnitTests.csproj", "{71E58E09-BEE4-4B19-BCF7-4C9BD71514FB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocks", "Mocks\Mocks.csproj", "{00E00484-BD00-40CD-B2CC-1CFA8E893972}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomerOrder.UnitTests", "CustomerOrder.UnitTests\CustomerOrder.UnitTests.csproj", "{226B8D34-99CF-4172-87DC-E20B39030CC0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web.Service", "Web.Service\Web.Service.csproj", "{EB1D3837-C58C-4F47-8B64-938E6013E8EB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0EE37B65-FCCB-44AE-B4F7-AED85FDEB072}.Debug|x64.ActiveCfg = Debug|x64 {0EE37B65-FCCB-44AE-B4F7-AED85FDEB072}.Debug|x64.Build.0 = Debug|x64 {0EE37B65-FCCB-44AE-B4F7-AED85FDEB072}.Debug|x64.Deploy.0 = Debug|x64 {0EE37B65-FCCB-44AE-B4F7-AED85FDEB072}.Release|x64.ActiveCfg = Release|x64 {0EE37B65-FCCB-44AE-B4F7-AED85FDEB072}.Release|x64.Build.0 = Release|x64 {0EE37B65-FCCB-44AE-B4F7-AED85FDEB072}.Release|x64.Deploy.0 = Release|x64 {5F0C7805-C91D-47E9-AEDE-946CADEA1C8F}.Debug|x64.ActiveCfg = Debug|x64 {5F0C7805-C91D-47E9-AEDE-946CADEA1C8F}.Debug|x64.Build.0 = Debug|x64 {5F0C7805-C91D-47E9-AEDE-946CADEA1C8F}.Release|x64.ActiveCfg = Release|x64 {5F0C7805-C91D-47E9-AEDE-946CADEA1C8F}.Release|x64.Build.0 = Release|x64 {1E7E813F-43D3-4D0B-8546-5E1023873F28}.Debug|x64.ActiveCfg = Debug|x64 {1E7E813F-43D3-4D0B-8546-5E1023873F28}.Debug|x64.Build.0 = Debug|x64 {1E7E813F-43D3-4D0B-8546-5E1023873F28}.Release|x64.ActiveCfg = Release|x64 {1E7E813F-43D3-4D0B-8546-5E1023873F28}.Release|x64.Build.0 = Release|x64 {4C5ACF3B-E6D1-4FBD-8B23-A9FA7BA6326E}.Debug|x64.ActiveCfg = Debug|x64 {4C5ACF3B-E6D1-4FBD-8B23-A9FA7BA6326E}.Debug|x64.Build.0 = Debug|x64 {4C5ACF3B-E6D1-4FBD-8B23-A9FA7BA6326E}.Release|x64.ActiveCfg = Release|x64 {4C5ACF3B-E6D1-4FBD-8B23-A9FA7BA6326E}.Release|x64.Build.0 = Release|x64 {A44FC2C5-6781-447E-80F5-7265B960B36A}.Debug|x64.ActiveCfg = Debug|x64 {A44FC2C5-6781-447E-80F5-7265B960B36A}.Debug|x64.Build.0 = Debug|x64 {A44FC2C5-6781-447E-80F5-7265B960B36A}.Release|x64.ActiveCfg = Release|x64 {A44FC2C5-6781-447E-80F5-7265B960B36A}.Release|x64.Build.0 = Release|x64 {714B1C61-FFA8-4A5E-8DD2-D0A290677293}.Debug|x64.ActiveCfg = Debug|x64 {714B1C61-FFA8-4A5E-8DD2-D0A290677293}.Debug|x64.Build.0 = Debug|x64 {714B1C61-FFA8-4A5E-8DD2-D0A290677293}.Release|x64.ActiveCfg = Release|x64 {714B1C61-FFA8-4A5E-8DD2-D0A290677293}.Release|x64.Build.0 = Release|x64 {7C404BC4-7589-488C-AB09-876E5B33B641}.Debug|x64.ActiveCfg = Debug|x64 {7C404BC4-7589-488C-AB09-876E5B33B641}.Debug|x64.Build.0 = Debug|x64 {7C404BC4-7589-488C-AB09-876E5B33B641}.Release|x64.ActiveCfg = Release|x64 {7C404BC4-7589-488C-AB09-876E5B33B641}.Release|x64.Build.0 = Release|x64 {9EC0063F-489E-43FE-94B5-BF5F89977CD3}.Debug|x64.ActiveCfg = Debug|x64 {9EC0063F-489E-43FE-94B5-BF5F89977CD3}.Debug|x64.Build.0 = Debug|x64 {9EC0063F-489E-43FE-94B5-BF5F89977CD3}.Release|x64.ActiveCfg = Release|x64 {9EC0063F-489E-43FE-94B5-BF5F89977CD3}.Release|x64.Build.0 = Release|x64 {4162F266-D657-4143-AA62-626C10D23561}.Debug|x64.ActiveCfg = Debug|x64 {4162F266-D657-4143-AA62-626C10D23561}.Debug|x64.Build.0 = Debug|x64 {4162F266-D657-4143-AA62-626C10D23561}.Release|x64.ActiveCfg = Release|x64 {4162F266-D657-4143-AA62-626C10D23561}.Release|x64.Build.0 = Release|x64 {7E9C2DFD-71A5-496D-AA4D-5EC53EAEB9AE}.Debug|x64.ActiveCfg = Debug|x64 {7E9C2DFD-71A5-496D-AA4D-5EC53EAEB9AE}.Debug|x64.Build.0 = Debug|x64 {7E9C2DFD-71A5-496D-AA4D-5EC53EAEB9AE}.Release|x64.ActiveCfg = Release|x64 {7E9C2DFD-71A5-496D-AA4D-5EC53EAEB9AE}.Release|x64.Build.0 = Release|x64 {71E58E09-BEE4-4B19-BCF7-4C9BD71514FB}.Debug|x64.ActiveCfg = Debug|x64 {71E58E09-BEE4-4B19-BCF7-4C9BD71514FB}.Debug|x64.Build.0 = Debug|x64 {71E58E09-BEE4-4B19-BCF7-4C9BD71514FB}.Release|x64.ActiveCfg = Release|x64 {71E58E09-BEE4-4B19-BCF7-4C9BD71514FB}.Release|x64.Build.0 = Release|x64 {00E00484-BD00-40CD-B2CC-1CFA8E893972}.Debug|x64.ActiveCfg = Debug|x64 {00E00484-BD00-40CD-B2CC-1CFA8E893972}.Debug|x64.Build.0 = Debug|x64 {00E00484-BD00-40CD-B2CC-1CFA8E893972}.Release|x64.ActiveCfg = Release|x64 {00E00484-BD00-40CD-B2CC-1CFA8E893972}.Release|x64.Build.0 = Release|x64 {226B8D34-99CF-4172-87DC-E20B39030CC0}.Debug|x64.ActiveCfg = Debug|x64 {226B8D34-99CF-4172-87DC-E20B39030CC0}.Debug|x64.Build.0 = Debug|x64 {226B8D34-99CF-4172-87DC-E20B39030CC0}.Release|x64.ActiveCfg = Release|x64 {226B8D34-99CF-4172-87DC-E20B39030CC0}.Release|x64.Build.0 = Release|x64 {EB1D3837-C58C-4F47-8B64-938E6013E8EB}.Debug|x64.ActiveCfg = Debug|Any CPU {EB1D3837-C58C-4F47-8B64-938E6013E8EB}.Debug|x64.Build.0 = Debug|Any CPU {EB1D3837-C58C-4F47-8B64-938E6013E8EB}.Release|x64.ActiveCfg = Release|Any CPU {EB1D3837-C58C-4F47-8B64-938E6013E8EB}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ReferenceApp/WebReferenceApplication/ApplicationPackageRoot/ApplicationManifest.xml ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/ApplicationParameters/Cloud.xml ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/ApplicationParameters/Local.1Node.xml ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/ApplicationParameters/Local.5Node.xml ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/PublishProfiles/Cloud.xml ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/PublishProfiles/Local.1Node.xml ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/PublishProfiles/Local.5Node.xml ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/Scripts/Deploy-FabricApplication.ps1 ================================================ <# .SYNOPSIS Deploys a Service Fabric application type to a cluster. .DESCRIPTION This script deploys a Service Fabric application type to a cluster. It is invoked by Visual Studio when deploying a Service Fabric Application project. .NOTES WARNING: This script file is invoked by Visual Studio. Its parameters must not be altered but its logic can be customized as necessary. .PARAMETER PublishProfileFile Path to the file containing the publish profile. .PARAMETER ApplicationPackagePath Path to the folder of the packaged Service Fabric application. .PARAMETER DeployOnly Indicates that the Service Fabric application should not be created or upgraded after registering the application type. .PARAMETER ApplicationParameter Hashtable of the Service Fabric application parameters to be used for the application. .PARAMETER UnregisterUnusedApplicationVersionsAfterUpgrade Indicates whether to unregister any unused application versions that exist after an upgrade is finished. .PARAMETER OverrideUpgradeBehavior Indicates the behavior used to override the upgrade settings specified by the publish profile. 'None' indicates that the upgrade settings will not be overridden. 'ForceUpgrade' indicates that an upgrade will occur with default settings, regardless of what is specified in the publish profile. 'VetoUpgrade' indicates that an upgrade will not occur, regardless of what is specified in the publish profile. .PARAMETER UseExistingClusterConnection Indicates that the script should make use of an existing cluster connection that has already been established in the PowerShell session. The cluster connection parameters configured in the publish profile are ignored. .PARAMETER OverwriteBehavior Overwrite Behavior if an application exists in the cluster with the same name. Available Options are Never, Always, SameAppTypeAndVersion. This setting is not applicable when upgrading an application. 'Never' will not remove the existing application. This is the default behavior. 'Always' will remove the existing application even if its Application type and Version is different from the application being created. 'SameAppTypeAndVersion' will remove the existing application only if its Application type and Version is same as the application being created. .PARAMETER SkipPackageValidation Switch signaling whether the package should be validated or not before deployment. .PARAMETER SecurityToken A security token for authentication to cluster management endpoints. Used for silent authentication to clusters that are protected by Azure Active Directory. .PARAMETER CopyPackageTimeoutSec Timeout in seconds for copying application package to image store. .EXAMPLE . Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' Deploy the application using the default package location for a Debug build. .EXAMPLE . Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' -DoNotCreateApplication Deploy the application but do not create the application instance. .EXAMPLE . Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' -ApplicationParameter @{CustomParameter1='MyValue'; CustomParameter2='MyValue'} Deploy the application by providing values for parameters that are defined in the application manifest. #> Param ( [String] $PublishProfileFile, [String] $ApplicationPackagePath, [Switch] $DeployOnly, [Hashtable] $ApplicationParameter, [Boolean] $UnregisterUnusedApplicationVersionsAfterUpgrade, [String] [ValidateSet('None', 'ForceUpgrade', 'VetoUpgrade')] $OverrideUpgradeBehavior = 'None', [Switch] $UseExistingClusterConnection, [String] [ValidateSet('Never','Always','SameAppTypeAndVersion')] $OverwriteBehavior = 'Never', [Switch] $SkipPackageValidation, [String] $SecurityToken, [int] $CopyPackageTimeoutSec ) function Read-XmlElementAsHashtable { Param ( [System.Xml.XmlElement] $Element ) $hashtable = @{} if ($Element.Attributes) { $Element.Attributes | ForEach-Object { $boolVal = $null if ([bool]::TryParse($_.Value, [ref]$boolVal)) { $hashtable[$_.Name] = $boolVal } else { $hashtable[$_.Name] = $_.Value } } } return $hashtable } function Read-PublishProfile { Param ( [ValidateScript({Test-Path $_ -PathType Leaf})] [String] $PublishProfileFile ) $publishProfileXml = [Xml] (Get-Content $PublishProfileFile) $publishProfile = @{} $publishProfile.ClusterConnectionParameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("ClusterConnectionParameters") $publishProfile.UpgradeDeployment = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("UpgradeDeployment") $publishProfile.CopyPackageParameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("CopyPackageParameters") if ($publishProfileXml.PublishProfile.Item("UpgradeDeployment")) { $publishProfile.UpgradeDeployment.Parameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("UpgradeDeployment").Item("Parameters") if ($publishProfile.UpgradeDeployment["Mode"]) { $publishProfile.UpgradeDeployment.Parameters[$publishProfile.UpgradeDeployment["Mode"]] = $true } } $publishProfileFolder = (Split-Path $PublishProfileFile) $publishProfile.ApplicationParameterFile = [System.IO.Path]::Combine($PublishProfileFolder, $publishProfileXml.PublishProfile.ApplicationParameterFile.Path) return $publishProfile } $LocalFolder = (Split-Path $MyInvocation.MyCommand.Path) if (!$PublishProfileFile) { $PublishProfileFile = "$LocalFolder\..\PublishProfiles\Local.xml" } if (!$ApplicationPackagePath) { $ApplicationPackagePath = "$LocalFolder\..\pkg\Release" } $ApplicationPackagePath = Resolve-Path $ApplicationPackagePath $publishProfile = Read-PublishProfile $PublishProfileFile if (-not $UseExistingClusterConnection) { $ClusterConnectionParameters = $publishProfile.ClusterConnectionParameters if ($SecurityToken) { $ClusterConnectionParameters["SecurityToken"] = $SecurityToken } try { [void](Connect-ServiceFabricCluster @ClusterConnectionParameters) } catch [System.Fabric.FabricObjectClosedException] { Write-Warning "Service Fabric cluster may not be connected." throw } } $RegKey = "HKLM:\SOFTWARE\Microsoft\Service Fabric SDK" $ModuleFolderPath = (Get-ItemProperty -Path $RegKey -Name FabricSDKPSModulePath).FabricSDKPSModulePath Import-Module "$ModuleFolderPath\ServiceFabricSDK.psm1" $IsUpgrade = ($publishProfile.UpgradeDeployment -and $publishProfile.UpgradeDeployment.Enabled -and $OverrideUpgradeBehavior -ne 'VetoUpgrade') -or $OverrideUpgradeBehavior -eq 'ForceUpgrade' $PublishParameters = @{ 'ApplicationPackagePath' = $ApplicationPackagePath 'ApplicationParameterFilePath' = $publishProfile.ApplicationParameterFile 'ApplicationParameter' = $ApplicationParameter 'ErrorAction' = 'Stop' } if ($publishProfile.CopyPackageParameters.CopyPackageTimeoutSec) { $PublishParameters['CopyPackageTimeoutSec'] = $publishProfile.CopyPackageParameters.CopyPackageTimeoutSec } if ($publishProfile.CopyPackageParameters.CompressPackage) { $PublishParameters['CompressPackage'] = $publishProfile.CopyPackageParameters.CompressPackage } # CopyPackageTimeoutSec parameter overrides the value from the publish profile if ($CopyPackageTimeoutSec) { $PublishParameters['CopyPackageTimeoutSec'] = $CopyPackageTimeoutSec } if ($IsUpgrade) { $Action = "RegisterAndUpgrade" if ($DeployOnly) { $Action = "Register" } $UpgradeParameters = $publishProfile.UpgradeDeployment.Parameters if ($OverrideUpgradeBehavior -eq 'ForceUpgrade') { # Warning: Do not alter these upgrade parameters. It will create an inconsistency with Visual Studio's behavior. $UpgradeParameters = @{ UnmonitoredAuto = $true; Force = $true } } $PublishParameters['Action'] = $Action $PublishParameters['UpgradeParameters'] = $UpgradeParameters $PublishParameters['UnregisterUnusedVersions'] = $UnregisterUnusedApplicationVersionsAfterUpgrade Publish-UpgradedServiceFabricApplication @PublishParameters } else { $Action = "RegisterAndCreate" if ($DeployOnly) { $Action = "Register" } $PublishParameters['Action'] = $Action $PublishParameters['OverwriteBehavior'] = $OverwriteBehavior $PublishParameters['SkipPackageValidation'] = $SkipPackageValidation Publish-NewServiceFabricApplication @PublishParameters } ================================================ FILE: ReferenceApp/WebReferenceApplication/WebReferenceApplication.sfproj ================================================  0ee37b65-fccb-44ae-b4f7-aed85fdeb072 1.5 v4.5.2 true 1.5 Debug x64 Release x64 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Service Fabric Tools\Microsoft.VisualStudio.Azure.Fabric.ApplicationProject.targets ================================================ FILE: ReferenceApp/WebReferenceApplication/app.config ================================================  ================================================ FILE: ReferenceApp/WebReferenceApplication/packages.config ================================================