Asp.net add multiply rows to CRM 2011 (2+ clients/User) - asp.net

I've extended the customer portal from MS for 2011 with functionality to add an order.
Now i came across a problem when 2 or more user try to create an order at the same time.
first I created the SalesOrder with:
order = new SalesOrder();
order.SalesOrderId = OrderID;
order.Name = string.Format("Order {0}", DateTime.Now);
order.CustomerId = parentCustomer;
order.PriceLevelId = priceLevel.ToEntityReference();
OrderID = XrmContext.Create(order);
and after this i added products(SalesOrderDetail) with a foreach:
foreach (var product in OrdredProducts)
{
productToAdd = new SalesOrderDetail
{
SalesOrderId = new CrmEntityReference(SalesOrder.EntityLogicalName,
OrderID),
ProductId = new EntityReference(Product.EntityLogicalName,
product.ProductID),
Quantity = product.Quantity
};
XrmContext.Create(productToAdd);
}
this works fine when just one user orders something. But if 2+ users I get error for both user.
so I changed the code to this:
order = new SalesOrder();
OrderID = Guid.NewGuid();
order.SalesOrderId = OrderID;
order.Name = string.Format("Order {0}", DateTime.Now); //:d
order.CustomerId = parentCustomer;
order.PriceLevelId = priceLevel.ToEntityReference();
XrmContext.AddObject(order);
foreach (var product in OrdredProducts)
{
productToAdd = new SalesOrderDetail
{
SalesOrderId = new CrmEntityReference(SalesOrder.EntityLogicalName,
OrderID),
ProductId = new EntityReference(Product.EntityLogicalName,
product.ProductID),
Quantity = product.Quantity
};
XrmContext.AddObject(productToAdd);
}
XrmContext.SaveChanges();
Now if 2+ Users orders something, just one User fails not both like the first try.
the Errors I've got as far(every time an other one):
ValidateOpen - Encountered disposed CrmDbConnection when it should not be disposed
SQL timeout expired.
An unexpected error occurred.
Error retrieving next number (currentordernumber) for organization {guid): return value is empty
System.InvalidOperationException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #F60BF6A2
does anyone have some suggestion where the problem could be? is it the SQL Server/CRM Server/IIS/my code or something different?
Additional Information
SQL Server and CRM Server are not on same machine
I get the same error when i test in VS2012 server(back-end is the same SQL/CRM server)
i get the same error when one user runs over IIS and one over VS2012(debugg)
edit
XrmContext is a XrmServiceContext type and this is derived from CrmOrganizationServiceContext and this one is generated with the crmsvcutil

if someone gets the same problem i solved it following:
first i created the SalesOrder and added it to the CRM:
public void AddToCrm(Entity entity)
{
XrmContext.AddObject(entity);
}
then I created all Orders(SalesOrderDetail) and added them to the CRM(same function as above).
And finally i saved it:
public void SaveToCrm()
{
XrmContext.SaveChanges();
}
this behaviour is like a transaction in the database.
so all other Order have to wait till this one is done.

Related

Exchange Web Services find item by unique id

I just started using Microsoft Exchange Web Services for the first time. Want I want to be able to do is the following:
Create Meeting
Update Meeting
Cancel/Delete Meeting
These meetings are created in an ASP.NET MVC application and saved into a SQL Server database. I simply wish to integrate this with the on site Exchange Server. So far, I'm able to created my meeting with the following code:
public static Task<string> CreateMeetingAsync(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
{
var tcs = new TaskCompletionSource<string>();
try
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = CredentialCache.DefaultNetworkCredentials;
//service.UseDefaultCredentials = true;
// I suspect the Service URL needs to be set from the user email address because this is then used to set the organiser
// of the appointment constructed below. The Organizer is a read-only field that cannot be manually set. (security measure)
service.AutodiscoverUrl(from);
//service.Url = new Uri(WebConfigurationManager.AppSettings["ExchangeServer"]);
Appointment meeting = new Appointment(service);
meeting.Subject = subject;
meeting.Body = "<span style=\"font-family:'Century Gothic'\" >" + body + "</span><br/><br/><br/>";
meeting.Body.BodyType = BodyType.HTML;
meeting.Start = begin;
meeting.End = end;
meeting.Location = location;
meeting.ReminderMinutesBeforeStart = 60;
foreach (string attendee in to)
{
meeting.RequiredAttendees.Add(attendee);
}
meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy);
tcs.TrySetResult(meeting.Id.UniqueId);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
return tcs.Task;
}
This successfully creates my meeting, places it into the user's calendar in outlook and sends a meeting request to all attendees. I noticed the following exception when attempting to call meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy); twice:
This operation can't be performed because this service object already has an ID. To update this service object, use the Update() method instead.
I thought: Great, it saves the item in exchange with a unique id. I'll save this ID in my application's database and use it later to edit/cancel the meeting. That is why I return the id: tcs.TrySetResult(meeting.Id.UniqueId);
This is saved nicely into my application's database:
Now, I am attempting to do the next part where I update the meeting, but I cannot find a way to search for the item based on the unique identifier that I'm saving. An example I found on code.msdn uses the service.FindItems() method with a query that searches the subject:
string querystring = "Subject:Lunch";
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Calendar, querystring, view);
I don't like this. There could be a chance that the user created a meeting outside of my application that coincidentally has the same subject, and here come's my application and cancel's it. I tried to determine wether it's possible to use the unique id in the query string, but this does not seem possible.
I did notice on the above query string page that the last property you can search on is (property is not specified) that searches in "all word phase properties.". I tried thus simply putting the id into the query, but this returns no results:
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Calendar, "AAMkADJhZDQzZWFmLWYxYTktNGI1Yi1iZTA5LWVmOTE3MmJiMGIxZgBGAAAAAAAqhOzrXRdvRoA6yPu9S/XnBwDXvBDBMebkTqUWix3HxZrnAAAA2LKLAAB5iS34oLxkSJIUht/+h9J1AAFlEVLAAAA=", view);
Use the Appointment.Bind static function, providing a service object and the ItemId saved in your database. Be aware with meeting workflow (invite, accept, reject) can re-create a meeting on the same calendar with a new ItemId. But if you are just looking at the meeting you make on your own calendar, you should be OK.

Panel using stored procedure - Code not reacting as expected

I have hit a small issue and hoping someone might be able to assist. I am using a panel - On the page load, it should list all the products as no category has been selected as per stored procedure (this works perfectly).
When a user clicks on a specific category, it should only show the products that have the specific CategoryID. When I run the code in SQL, it works a dream for this part too, so assume the stored procedure is ok.
At
CategoryID = CategoryID
in GetProducts, I get
Warning: Assignment made to same variable; did you mean to assign something else?
However I am following a tutorial video and this works fine. Is there another silly error that is preventing it from working?
I think I have included all the required code - sorry if its a bit overkill!!
Thanks as ever in advance - Jack
Code behind pnlCategories:
private void GetProducts(int CategoryID)
{
ShoppingCart k = new ShoppingCart();
{
CategoryID = CategoryID;
};
Error identified - additional ";" added at following line:
ShoppingCart k = new ShoppingCart();
Code now reads
ShoppingCart k = new ShoppingCart()
{
CategoryID = CategoryID
};
and functions as expected!
that looks like a c# error and not a SQL Server error.
The problem is here in your GetProducts method. CategoryID = CategoryID;
C# is case sensitive. If you check your tutorial carefully, one of these will probably be lower case. Make sure you type that carefully.
try code change below and see where the compiler complains.
CategoryID = categoryID;
private void GetProducts(int CategoryID)
{
ShoppingCart k = new ShoppingCart();
{
CategoryID = CategoryID;
};
dlProducts.DataSource = null;
dlProducts.DataSource = k.GetProdcuts();
dlProducts.DataBind();
}

WCF Transaction with multiple inserts

When creating a user, entries are required in multiple tables. I am trying to create a transaction that creates a new entry into one table and then pass the new entityid into the parent table and so on. The error I am getting is
The transaction manager has disabled its support for remote/network
transactions. (Exception from HRESULT: 0x8004D024)
I believe this is caused by creating multiple connections within a single TransactionScope, but I am unsure on what the best/most efficient way of doing this is.
[OperationBehavior(TransactionScopeRequired = true)]
public int CreateUser(CreateUserData createData)
{
// Create a new family group and get the ID
var familyGroupId = createData.FamilyGroupId ?? CreateFamilyGroup();
// Create the APUser and get the Id
var apUserId = CreateAPUser(createData.UserId, familyGroupId);
// Create the institution user and get the Id
var institutionUserId = CreateInsUser(apUserId, createData.AlternateId, createData.InstitutionId);
// Create the investigator group user and return the Id
return AddUserToGroup(createData.InvestigatorGroupId, institutionUserId);
}
This is an example of one of the function calls, all the other ones follow the same format
public int CreateFamilyGroup(string familyGroupName)
{
var familyRepo = _FamilyRepo ?? new FamilyGroupRepository();
var familyGroup = new FamilyGroup() {CreationDate = DateTime.Now};
return familyRepo.AddFamilyGroup(familyGroup);
}
And the repository call for this is as follows
public int AddFamilyGroup(FamilyGroup familyGroup)
{
using (var context = new GameDbContext())
{
var newGroup = context.FamilyGroups.Add(familyGroup);
context.SaveChanges();
return newGroup.FamilyGroupId;
}
}
I believe this is caused by creating multiple connections within a single TransactionScope
Yes, that is the problem. It does not really matter how you avoid that as long you avoid it. A common thing to do is to have one connection and one EF context per WCF request. You need to find a way to pass that EF context along.
The method AddFamilyGroup illustrates a common anti-pattern with EF: You are using EF as a CRUD facility. It's supposed to me more like a live object graph connected to the database. The entire WCF request should share the same EF context. If you move in that direction the problem goes away.

Publish Transaction Information Type Mismatch Error

Using Tridion 2009, SP1, hence the old COM+ TOM API. I'm trying to get information of a PublishTransaction but getting an error each time I call the PublishTransaction.Information property.
Here is my code:
try
{
var pubTrans = (PublishTransaction)tdse.GetObject("tcm:0-166535-66560",
EnumOpenMode.OpenModeView);
Console.WriteLine("transaction id=" + pubTrans.ID);
Console.WriteLine("transaction itemtype=" + pubTrans.itemType.ToString());
Console.WriteLine("transaction info=" + pubTrans.Information);
}
catch (Exception e)
{
Console.WriteLine(e.Message, e.StackTrace);
}
Above, the transaction ID and Item Type print fine. I have other code where the Delete method works fine, but any time I try and get the Information, it blows up.
Here is the error:
<tcm:Error xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ErrorCode="D"
Category="18" Source="Kernel" Severity="1">
<tcm:Line Cause="false" MessageID="16138">
<![CDATA[Unable to get Information of Unknown (tcm:0-166535-66560).]]>
<tcm:Token>RESID_4485</tcm:Token><tcm:Token>Information</tcm:Token>
<tcm:Token>RESID_4663</tcm:Token><tcm:Token>tcm:0-166535-66560</tcm:Token>
</tcm:Line>
<tcm:Line ErrorCode="D" Cause="true"><![CDATA[Type mismatch]]></tcm:Line>
<tcm:Details>
<tcm:CallStack>
<tcm:Location>PublishTransaction.Information</tcm:Location>
<tcm:Location>PublishTransaction.Information</tcm:Location>
</tcm:CallStack>
</tcm:Details>
</tcm:Error>
I've searched the SDL Tridion World forum and couldn't find the answer. Am I missing a hotfix, should I contact Support, or is there another way to get the transaction info?
I am not really sure (without digging further at this time of night), but is the 'Information' property actually an XMLElement rather than a string as the docs say? When you use a debugger, are you able to place a watch on this property to see what it contains?
I tried this in another way to get the PublishTransaction Information. Below is the code:-
PublishTransaction pubTrans = (PublishTransaction)tdse.GetObject(
"tcm:0-4294103-66560",
EnumOpenMode.OpenModeView,
null,
XMLReadFilter.XMLReadNull);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(pubTrans.GetXML(XMLReadFilter.XMLReadAll));
XmlNamespaceManager nameSpace = new XmlNamespaceManager(xmlDoc.NameTable);
nameSpace.AddNamespace("tcm", "http://www.tridion.com/ContentManager/5.0");
nameSpace.AddNamespace("xlink", "http://www.w3.org/1999/xlink");
Console.WriteLine("transaction id=" + pubTrans.ID);
Console.WriteLine("transaction itemtype=" + pubTrans.itemType.ToString());
EnumPublishTransactionState transState = pubTrans.get_State();
if (transState == EnumPublishTransactionState.Failed)
Console.WriteLine("transaction info=" +
xmlDoc.SelectSingleNode("/tcm:PublishTransaction/tcm:Data/tcm:Information",
nameSpace).InnerText);
I don't have a working environment, so I am just looking into whatever existing code I have available. This is snippet from the Event system which deletes a Queue item only when you have Admin privileges:
public void OnPublicationPublishPost(Publication publication, IXMLDOMDocument2 publishResult)
{
TDSE tdse = Utilities.GetTDSEInstance();
publishResult.setProperty("SelectionNamespaces", "xmlns:tcm=\"http://www.tridion.com/ContentManager/5.0\"");
PublishTransaction publishTransaction = Utilities.GetTridionItem<PublishTransaction>(publishResult.selectSingleNode("/*/*").attributes[2].text, null) as PublishTransaction;
User user = Utilities.GetTridionItem<User>(publishResult.selectSingleNode("/tcm:PublishResponse/tcm:PublisherRequest/tcm:User").attributes[0].text, null) as User;
TDSPrivileges isAdmin = user.privileges;
if (isAdmin != TDSPrivileges.TdsPrivilegeSystemAdministrator)
{
publishTransaction.Delete();
}
}

How to save a related entity using Entity Framework in asp.net

I am pretty new to Entity Framework. I am getting an error as
An object with a temporary EntityKey value cannot be attached to an
object context
I think I am doing something wrong.
I have a Customer table and Address table where the Address table has customer's ID as foreign key.
I want to add a new address to the customer entity and keep in session and in next call I want to save it. this is only an example.
using (var db = new MyModel())
{
Customer cust = db.Customers.SingleOrDefault(c => C.ID == 1);
Address addr = new Address();
addr.Street = "123 super st";
cust.Addresses.Add(addr);
Session["customer"] = cust;
}
Customer SessionCustomer = (Customer)Session["customer"];
Customer.Comments = "Added new address";
using (var db = new MyModel())
{
db.Customers.Attach(SessionCustomer); //This throws exception: An object with a temporary EntityKey value cannot be attached to an object context
db.ObjectStateManager.ChangeObjectState(SessionCustomer, System.Data.EntityState.Modified);
db.SaveChanges();
}
Any help is appreciated. thank you.
Try using db.Customers.AddObject() for reattaching object to datacontext.
Take also a look at this: http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.addobject.aspx
Cheers

Resources