I have a workflow, that at a certain point, needs to be triggered recursively.
I can't seem to figure out how to do this.
I tried the following code but context ends up being null??
private void codeTriggerChildren_ExecuteCode(object sender, EventArgs e)
{
ActivityExecutionContext context = sender as ActivityExecutionContext;
//context is null here?!
IStartWorkflow aWorkflow = context.GetService(typeof(ApprovalFlow)) as IStartWorkflow;
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("Parm1", "foo");
parameters.Add("Parm2", "bar");
Guid guid = aWorkflow.StartWorkflow(typeof(ApprovalFlow), parameters);
}
Primarily the problem here is that the sender in this case is a CodeActivity not an ActivityExecutionContext. So this code fails at the first hurdle.
Here is an example of custom activity that can do what you are after:-
public class RecurseApproval : Activity
{
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
IStartWorkflow aWorkflow = executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow;
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("Param1", "Foo");
parameters.Add("Param2", "bar");
Guid guid = aWorkflow.StartWorkflow(typeof(ApprovalWorkflow), parameters);
return ActivityExecutionStatus.Closed;
}
}
Note that the GetService gets type of IStartWorkflow.
Your sender is of type CodeActivity not ActivityExecutionContext. You need to create a custom activity and override the Execute method which will pass you a ActivityExecutionContext.
Related
Ok first things first. This is some exception information given by the support team. I know the line and code where it happens. It happens in a FirstOrDefault call over a dictionary obtained from cache.
1) Exception Information
*********************************************
Exception Type: System.InvalidOperationException
Message: Collection was modified; enumeration operation may not execute.
Data: System.Collections.ListDictionaryInternal
Now I wanted to simulate the problem and I could do it in a simple ASP.net application.
My page has 2 Buttons - Button_Process and Button_Add
The code behind is as follows:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var data = Cache["key"];
if (data == null)
{
var dict = new Dictionary<int, string>();
for (int i = 0; i < 10; i++)
{
dict.Add(i, "i");
}
Cache["key"] = dict;
}
}
}
protected void ButtonProcess_Click(object sender, EventArgs e)
{
var data = Cache["key"] as Dictionary<int, string>;
if (data != null)
{
foreach (var d in data.Values) //In actual code there is FirstOrDefault here
{
Thread.Sleep(1000);
if (d.Contains("5"))
{
//some operation
}
}
}
}
protected void Button2_Click(object sender, EventArgs e)
{
var data = Cache["key"] as Dictionary<int, string>;
if (data != null)
{
data.Add(new Random().Next(), "101");
Cache["key"] = data;
}
}
}
Now assume there are 2 requests:
Request 1 - Someone clicks on button_Process and some operation on cache object is taking place
Request 2 - Someone clicks on button_Add and the first person gets an exception - collection modified blah blah
I understand the problem - it is happening because we are accessing same bit of memory. I have 2 solutions in my mind:
1. I use a for loop instead of for each (to replace FirstOrDefault in actual code) - I dunno how efficient this operation will be after I make the changes. - I don't ever delete any item from cache so I was thinking of this solution
2. I put some lock over cache object or something on those lines - but I dunno exactly where and how should I lock this object.
Please help me with this. I am not able to figure out an efficient solution. What is the best way to handle such situations?
This happens because you're working directly with object, locating in cache. Good practise, to avoid those exceptions and other wierd behavior (when you accidentally modify cache object) is working with copy of cache data. And there are several ways of achieving it, like doing clone or some kind of deep copy. What i prefer is keeping objects in cache serialized (any kind you like - json/xml/binary or w/e else), since (de)serialization makes a deep copy of your object. Following small code snippet will clarify things:
public static class CacheManager
{
private static readonly Cache MyCache = HttpRuntime.Cache;
public static void Put<T>(T data, string key)
{
MyCache.Insert(key, Serialize(data));
}
public static T Get<T>(string key)
{
var data = MyCache.Get(key) as string;
if (data != null)
return Deserialize<T>(data);
return default(T);
}
private static string Serialize(object data)
{
//this is Newtonsoft.Json serializer, but you can use the one you like
return JsonConvert.SerializeObject(data);
}
private static T Deserialize<T>(string data)
{
return JsonConvert.DeserializeObject<T>(data);
}
}
And usage:
var myObj = new Dictionary<int, int>();
CacheManager.Put(myObj, "myObj");
//...
var anotherObj = CacheManager.Get<Dictionary<int, int>>("myObj");
Check Task Parallel Library for .NET 3.5. It has Concurrent Collections such as ConcurrentStack, ConcurentQueue and ConcurrentDictionary.
http://www.nuget.org/packages/TaskParallelLibrary
The problem is that the cache object is global for appdomain and the data stored in are shared between all request.
The only solution to this problem is to activate a lock when you want to access to the collection and then release the lock (https://msdn.microsoft.com/en-us/library/vstudio/c5kehkcz%28v=vs.100%29.aspx).
(sorry form my bad english)
I'm using EF 5 with Web Forms (ASP.NET 4.5), with the "one DbContext instance per request" approach.
But this situation is a bit complicated: I have a multi-step create/edit screen, and I store the current entity in Session, then I manipulate it and in the final step, I commit it to the Database.
Creating a new instance was fine, but I can't for the life of me edit an existing entity... Because it's another request, my original DbContext instance was lost and when I attach it to a new one, I get the An entity object cannot be referenced by multiple instances of IEntityChangeTracker error.
My code is far too complex to post here, but I'll try and summarize it accurately:
My DbContext:
public class AppContext : DbContext
{
// DbSet declarations...
public static AppContext Current {
get { var context = HttpContext.Current.Items["Contexts.AppContext"] as AppContext;
if (context == null)
{
context = new AppContext();
HttpContext.Current.Items["Contexts.AppContext"] = context;
}
return context;
}
}
}
An example of what the page code looks like:
protected void Page_Load(object sender, EventArgs e)
{
int? id = null; // After this, I try to get it from the QueryString, parse it, etc.. Omitted for sake of brevity
// If I have an ID, it means I'm editing...
Session["Product"] = id.HasValue ? new Product() : AppContext.Current.Products.Find(id));
MethodToPopulateFields(); // Internally, it uses the Session variable
}
protected void Step1(){ // through n
// Manipulates the Session["Product"] based on page input...
}
protected void Save(){
var product = Session["Product"] as Product;
if(product.ID == 0)
product = AppContext.Current.Products.Add(product);
// throws an exception:
// AppContext.Current.Entry(product).State = EntityState.Modified;
// this too:
// AppContext.Products.Attach(product);
AppContext.Current.SaveChanges();
}
I know I can get the old entity from the database, update it manually and save, all in the last step, but I really don't want to do that...
Thank you.
Try calling
AppContext.Current.Entry(product).State = EntityState.Detached;
in the first method.
I am in a need to intercept all of the html that will be sent to the browser and replace some tags that are there. this will need to be done globally and for every view. what is the best way to do this in ASP.NET MVC 3 or 4 using C#? In past I have done this in ASP.net Webforms using the 'response.filter' in the Global.asax (vb)
Private Sub Global_PreRequestHandlerExecute(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRequestHandlerExecute
Response.Filter = New ReplaceTags(Response.Filter)
End Sub
this calls a class I created that inherits from the system.io.stream and that walked through the html to replace all the tags.
I have no idea as to how to do this in ASP.NET MVC 4 using C#. As you might have noticed I am a completely newbee in the MVC world.
You could still use a response filter in ASP.NET MVC:
public class ReplaceTagsFilter : MemoryStream
{
private readonly Stream _response;
public ReplaceTagsFilter(Stream response)
{
_response = response;
}
public override void Write(byte[] buffer, int offset, int count)
{
var html = Encoding.UTF8.GetString(buffer);
html = ReplaceTags(html);
buffer = Encoding.UTF8.GetBytes(html);
_response.Write(buffer, offset, buffer.Length);
}
private string ReplaceTags(string html)
{
// TODO: go ahead and implement the filtering logic
throw new NotImplementedException();
}
}
and then write a custom action filter which will register the response filter:
public class ReplaceTagsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var response = filterContext.HttpContext.Response;
response.Filter = new ReplaceTagsFilter(response.Filter);
}
}
and now all that's left is decorate the controllers/actions that you want to be applied this filter:
[ReplaceTags]
public ActionResult Index()
{
return View();
}
or register it as a global action filter in Global.asax if you want to apply to all actions.
The answer is correct but. After using it for a while I came across a case when the response is split in many parts so that html is incorrect
Part 1:
<html>.....<labe
Part 2:
l/>...</html>
Also partial renders may make unexpected cases. Their html is out of the main stream too.
So my solution is to do it in the Flush method after all streaming is done.
/// <summary>
/// Insert messages and script to display on client when a partial view is returned
/// </summary>
private class ResponseFilter : MemoryStream
{
private readonly Stream _response;
private readonly IList<object> _detachMessages;
public override void Flush()
{
// add messages and remove
// filter is called for a number of methods on one page (BeginForm, RenderPartial...)
// so that we don't need to add it more than once
var html = MessageAndScript(_detachMessages);
var buffer = Encoding.UTF8.GetBytes(html);
_detachMessages.Clear();
_response.Write(buffer, 0, buffer.Length);
base.Flush();
}
public ResponseFilter(Stream response, IList<object> detachMessages)
{
_response = response;
_detachMessages = detachMessages;
}
public override void Write(byte[] buffer, int offset, int count)
{
_response.Write(buffer, offset, buffer.Length);
}
private static string MessageAndScript(IList<object> detachMessages)
{
if (detachMessages.Count == 0)
return null;
var javascript = CustomJavaScriptSerializer.Instance.Serialize(detachMessages);
return "$(function(){var messages = " + javascript + #";
// display messages
base.ajaxHelper.displayMessages(messages);
})";
}
}
I have searched the site for an answer to this question, but I cannot seem to figure this one out.
I have use the NewGuid() method many times and it has worked greate. But now for some reason it creates an empty Guid.
Here is my code:
// Class of the Guid Object
public class CardUserAccount
{
// User ID of the user's profile
public Guid UserId { get; set; }
}
//Page object where method is called
Public partial class CreateSale : System.Web.UI.UserControl
{
// Create the UserProfile object
public CardUserAccount profile = new CardUserAccount();
protected void ContinueButton_Click(object sender, EventArgs e)
{
Guid _userId = Guid.NewGuid();
profile.UserId = _userId;
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
// Method to add object to database
SubmitProfile(profile);
}
I then call a simple linq to entities method to add the object to the entity object.
I have double checked it and I am not overwriting it anywhere.
However could it be a problem that I am creating the profile object outside of the page_load method. I thought this would not affect the object during postback.
I would appreciate the help
Is this actual code? Because you declare and initialize the variable, then do nothing with it.
If you intend to overwrite a field value, you should not declare that field inside this method.
I have written a nifty function that will accept a system.object, reflect on its properties and serialize the object into a JSON string. It looks like this:
public class JSONSerializer
{
public string Serialize(object obj)
Now, I want to be able to do this to serialize a dynamic/ExpandoObject, but because my serializer uses reflection, it isn't able to do it. What's the workaround?
public class Test
{
public dynamic MakeDynamicCat()
{
dynamic newCat = new ExpandoObject();
newCat.Name = "Polly";
newCat.Pedigree = new ExpandoObject();
newCat.Pedigree.Breed = "Whatever";
return newCat;
}
public void SerializeCat()
{
new JSONSerializer().Serialize(MakeDynamicCat());
}
}
I think, this question is very similar: How do I reflect over the members of dynamic object?
At least the answers should help you too.