Skip to content
padzikm edited this page Dec 11, 2015 · 10 revisions

Example of this you can find in ProducDrafts controller

Service private data

Sometimes you don't want to create commands to handle them inside system asynchronously, but rather want to enable users simple crud and give them response immediately. There is one rule you must remember - you can do crud only within one service for data that hasn't been published yet to other services - this is private service data. If you break this rule and allow to modify public service data without publishing this change to others, system may end up in inconsistent state. For example if you want to delete resource that has been already published, you can't do it without nottifying other services, because other service will have resourceId of a resource that no longer exists, or even worse - it will have resourceId, that will point to newly created other resource after deletion previous one. The same is for editing resources.

Create

Handling creating request is like handling any other requests, with restriction that only one service, the one which data is created, can handle request. So when post request comes, it can be only one service that will respond to it. This isn't validated by infrastructure, but if you don't want other service to accidently handle private in some way, you sould validate this by yourself.

Update

If in updating resource there is only data from one service - resource owner - it's just normal request for display and handle post action.
Difference is when resource that user updates contains public data - eg ids of some other resources - from other services. In this case you can still render form, but you will be able to fill inputs only with data from one service, because other services don't know that there exists this resource that has reference to their resources by holding specific ids, as it hasn't been published yet. Because user wants to edit all fields and not to fill some of them again from scratch, service can leave "breadcrumbs" with requests to include some specific data when rendering current page. Let's consider simple update action:

[HttpGet]
[InternalAction]
public ActionResult Update(Guid privateModelId)
{
}

[HttpPost]
[InternalAction]
public ActionResult Update(PrivateModel model, IEnumerable<Guid> OtherServiceIds)
{
}

Because updated resource includes public data from other service, there must be publicly defined data from that service, which updating service can receive in action method. Furthermore as parameters are by default binded by names and form data is submitted in inputname=value way, there is a conclusion, that on this specific page there must be an element named OtherServiceIds. Moreover because this is data defined as public on this page, so other services can receive it, there must only one service that provides this data. In a result, updating service can leave breadcrumbs to other services saying: "if you are the one that renders OtherServiceIds element, please include data with this specific ids". What does "include data" mean? It means that if user submits form without changing it, this requested data will be send in post data, so for example in case of listbox specifc items, which values are specified in breadcrumbs, have to be selected from the begining. Including breadcrumbs looks like below:

[HttpGet]
[InternalAction]
public ActionResult Update(Guid privateModelId)
{
    var model = create_model(privateModelId);
    var breadcrumbs = new Dictionary<string,List<ServicePublicData>>();
    var list = model.OtherServiceIds.Select(p => new ServicePublicData() { Id = p }).ToList();
    breadcrumbs.Add("OtherServiceIds", list);
    var viewModel = new ViewModel(widgetId, render model action, breadcrumbs);
    return ViewModel(viewModel);
}

Beacuse we make request for specific element, we refer to it with this element's name and include for it requested values. These values are in ServicePublicData, which can only allow to include id, status and datetime, as these are the only values that can be published outside service to others, so these are the only values that updating service can know.
To pass breadcrumbs to interested services breadcrumbs are stored in TempData dictionary, because it's available for all components during current request. Important thing is that breadcrumbs are gathered and stored in TempData after all services return their view models, so they can refer to them when they render their view models. While rendering view models interested service can look into TempData and check if any breadcrumbs were left for components that are currently rendered - if so, then they can get this breadcrumbs and include requested values in rendered component. It's also very simple to include this kind of checking in template views - when element is rendered template checks if in TempData there are any elements that match specific element and if so it includes these values appropriately.
Because breadcrumbs are only valid insie one specific request, they are removed after all view models finish rendering.

Delete

Deleting resource is just like creating one - nothing unusual and only remember that only one service can handle this request.

Preview

Displaying user preview of created resource is different from other crud operations, because when created resource includes public data from other services, these data also need to be displayed, but in this case we can't leave breadcrumbs for other services like in update. That's because we don't know any public elements that will provide requested data - when displaying form, updating service knows that it will receive data with specific public names, but here there is no form and data that is send to server, so requesting service can't know what element to ask for including specific values and "including" now means nothing when we want to display it and not send this data back. If we specify public elements for displaying data where there is no logical justification for it, then we will introduce coupling between services and we don't want that.
One solution to this is to put preview option while editing resource, because all needed data is right in place. We can't send it to server in post request and return preview page, because as this is private resource only one service can handle post request. We can't also send form data in get request from security reasons. To solve this, we can store form data in browser and request for preview page in new window, passing this new page previously stored data. In preview page all services interested in displaying form data will include javascript code, that on page load will get data that are interested in from stored or passed data and render it. Remember, that this only works when data is already in browser, so when you want to display resource preview from other pages, you must find other way, or change crud to simple commands that will execute very fast and for example return crud results to a user using signalr.

Clone this wiki locally