EventReceiver doesn't work correctly - c#

I've got an EventReceiver in my SharePoint application where I'm overriding ItemAdding and ItemUpdating methods:
public override void ItemAdding(SPItemEventProperties properties)
{
SPWeb web = properties.OpenWeb();
switch (properties.ListTitle)
{
//some cases
case "Employees":
if (properties.AfterProperties["User"] != null)
{
SPUser user = web.SiteUsers
[
properties.AfterProperties["User"].ToString().Substring
(
properties.AfterProperties["User"].ToString().IndexOf(";#") + 2
)
];
properties.AfterProperties["Title"] = user.Name;
}
break;
}
base.ItemAdding(properties);
}
Code in both methods is exactly the same. But sometimes Title field remains empty after adding an item to list. And if I update that item (without any changes) Title field is filled by username correctly.

I see two potential issues in your code:
processing properties.AfterProperties["User"] by parsing it. It would be better to use code like this (SPUserFieldValue)properties.ListItem.Fields["User"].GetFieldValue(properties.properties.AfterProperties["User"].ToString()). This way suggested by MSDN.
Using SiteUsers indexer throws Exception when user is not found in the collection. You should wrap it by try ... catch statement. It can happen when user is used for the first time in your site collection.

Related

Nopcommerce Update entity issue

Using NopCommerce 3.8, Visual Studio 2015 proff.
I have created a plugin that is responsible for making restful calls to my Web API that exposes a different DB to that of Nop.
The process is run via a nop Task, it successfully pulls the data back and i can step through and manipulate as i see fit, no issues so far.
Issue comes when i try to update a record on the product table, i perform the update... but nothing happens no change, no error.
I believe this is due to the Context having no idea about my newly instantiated product object, however I'm drawing a blank on what i need to do in relation to my particular example.
Similar questions usually reference a "model" object that is part of the parameter of the method call, "model" has the method ToEntity which seems to be the answer in similar question in stack.
However my example doesn't have the ToEntity class/method possibly because my parameter is actually a list of products. To Clarify here my code.
Method in RestClient.cs
public async Task<List<T>> GetAsync()
{
try
{
var httpClient = new HttpClient();
var json = await httpClient.GetStringAsync(ApiControllerURL);
var taskModels = JsonConvert.DeserializeObject<List<T>>(json);
return taskModels;
}
catch (Exception e)
{
return null;
}
}
Method in my Service Class
public async Task<List<MWProduct>> GetProductsAsync()
{
RestClient<MWProduct> restClient = new RestClient<MWProduct>(ApiConst.Products);
var productsList = await restClient.GetAsync();
InsertSyncProd(productsList.Select(x => x).ToList());
return productsList;
}
private void InsertSyncProd(List<MWProduct> inserted)
{
var model = inserted.Select(x =>
{
switch (x.AD_Action)
{
case "I":
//_productService.InsertProduct(row);
break;
case "U":
UpdateSyncProd(inserted);
.....
Then the method to bind and update
private void UpdateSyncProd(List<MWProduct> inserted)
{
var me = inserted.Select(x =>
{
var productEnt = _productRepos.Table.FirstOrDefault(ent => ent.Sku == x.Sku.ToString());
if(productEnt != null)
{
productEnt.Sku = x.Sku.ToString();
productEnt.ShortDescription = x.ShortDescription;
productEnt.FullDescription = x.FullDescription;
productEnt.Name = x.Name;
productEnt.Height = x.Pd_height != null ? Convert.ToDecimal(x.Pd_height) : 0;
productEnt.Width = x.Pd_width != null ? Convert.ToDecimal(x.Pd_width) : 0;
productEnt.Length = x.Pd_depth != null ? Convert.ToDecimal(x.Pd_depth) : 0;
productEnt.UpdatedOnUtc = DateTime.UtcNow;
}
//TODO: set to entity so context nows and can update
_productService.UpdateProduct(productEnt);
return productEnt;
});
}
So as you can see, I get the data and pass data through to certain method based on a result. From that list in the method I iterate over, and pull the the entity from the table, then update via the product service using that manipulated entity.
So what am I missing here, I'm sure its 1 step, and i think it may be either be because 1) The context still has no idea about the entity in question, or 2) Its Incorrect calls.
Summary
Update is not updating, possibly due to context having no knowledge OR my methodology is wrong. (probably both).
UPDATE:
I added some logger.inertlog all around my service, it runs through fine, all to the point of the call of update. But again I check the product and nothing has changed in the admin section.
plugin
I have provided the full source as i think maybe this has something to do with the rest of the code setup possibly?
UPDATE:
Added the following for testin on my execute method.
var myprod = _productRepos.GetById(4852);
myprod.ShortDescription = "db test";
productRepos.Update(myprod);
This successfully updates the product description. I moved my methods from my service into the task class but still no luck. The more i look at it the more im thinking that my async is killing off the db context somehow.
Turned of async and bound the getbyid to a new product, also removed the lambda for the switch and changed it to a foreach loop. Seems to finally update the results.
Cannot confirm if async is the culprit, currently the web api seems to be returning the same result even though the data has changed (some wierd caching by deafult in .net core? ) so im creating a new question for that.
UPDATE: It appears that the issue stems from poor debugging of async. Each instance I am trying to iterate over an await call, simply put im trying to iterate over a collection that technically may or may not be completed yet. And probably due to poor debugging, I was not aware.
So answer await your collection Then iterate after.

session does not appear in the label

I created session to move data between pages using c# asp.net but the result does not appear and the program does not give me error in the code
first page code:
Session["New1"] = desc1.Text;
to send data to Label in Second page
code:
var userType = (string)Session["New1"];
if (userType != null)
{
Label1.Text = userType.ToString() ;
}
else
{
// test "2" etc
}
Try this,
if (Session["New1"]!= null)
{
Label1.Text = Session["New1"].ToString() ;
}
else
{
// test "2" etc
}
Try explicitly checking of your Session variable exists before attempting to use it to avoid any null-reference issues :
// Explicitly check that it exists
if (Session["New1"] != null)
{
// Then grab it (if it is a non-string type, then you can use as to cast it
// (e.g. a List might use Session["List"] as List<Widget>;)
Label1.Text = Convert.ToString(Session["New1"]);
}
else
{
// Do something here
}
This assumes that your value will be set prior to this code getting called. Additionally, any hiccups to the web server (e.g. timeouts, restarts, major exceptions, etc.) will clear all of the values within the Session.

CRM Plugin Error The given key was not present in the dictionary

I developed a CRM plugin that gets triggered when creating a Case entity. The Case has a N:1 relationship with another custom entity. Short story, when a field "new_CaseAssign" from the custom entity is set to 1, then the plugin will generate a Task assigned to Case Owner.
However the problem is that the field "new_CaseAssign" is newly added so most of the custom entity records don't have this field set yet, which causes the plugins to error out with "The given key was not present in the dictionary". If the custom field has value, then it's no problem.
What would be the best way to handle this situation? I tried customEntity.Attributes.Contains("new_CaseAssign") like below codes but no success:
var new_CaseAssign = customEntity.Attributes["new_CaseAssign"];
if ((customEntity.Attributes.Contains("new_CaseAssign")) && (bool)new_CaseAssign)
{
activityEntity.Attributes.Add("ownerid", incident.Attributes["ownerid"]);
}
else
{ //something else
}
Any suggestions is appreciated. Thanks much.
The line:
var new_CaseAssign = customEntity.Attributes["new_CaseAssign"];
is probably causing the exception. You could rewrite the code as:
bool new_CaseAssign = false;
if (customEntity.Attributes.Contains("new_CaseAssign"))
new_CaseAssign = (bool) customEntity.Attributes["new_CaseAssign"];
if (new_CaseAssign) {
activityEntity.Attributes.Add("ownerid", incident.Attributes["ownerid"]);
}
else { //something else
}
So first check contains before trying to access the key.
Loathing's answer is partially correct, in fact you are accessing the attribute before the check if is present or not. Normally I also check if the attribute it's not null before the cast.
The second error is with the field name, you are using late bound style, this means you need to use the logical name instead of the schema name, so the field name is new_caseassign (all lower case) instead of new_CaseAssign.
if ((customEntity.Attributes.Contains("new_caseassign")) && customEntity.Attributes["new_caseassign"] != null)
{
if ((bool)customEntity.Attributes["new_caseassign"])
{
activityEntity.Attributes.Add("ownerid", incident.Attributes["ownerid"]);
}
}
else
{ //something else
}

Any use to grab a SPListItem by multiple means in an event receiver?

I am working on supporting code in a custom event receiver developed about 6 years ago... There was no source code, so we had to reflect the production assembly, and are working on cleaning it up before working.
In the code, I came across this, and I can't tell why it would be done, and I don't know enough about SharePoint to be able to know if there is a reason it has to be done this way, or if the original coder was an idiot (both are possible...)
public override void ItemAdded(SPItemEventProperties properties)
{
Trace.WriteLine("ItemAdded() invoked.");
base.DisableEventFiring();
base.ItemAdded(properties);
try
{
SPContext context = SPContext.GetContext(properties.OpenWeb());
SPUserToken userToken = context.Site.SystemAccount.UserToken;
using (SPSite site = new SPSite(context.Site.ID, userToken))
using (SPWeb web = site.OpenWeb(context.Web.ID))
{
SPListItem listItem = null;
try
{
listItem = web.GetListItem(properties.ListItem.Url);
web.AllowUnsafeUpdates = true;
}
catch
{
Trace.WriteLine("No Url properties, we must be running in CLI mode. Exiting...");
}
if (listItem != null)
{
SPList parentList = listItem.ParentList;
listItem = parentList.GetItemById(properties.ListItemId);
}
...
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
}
finally
{
base.EnableEventFiring();
}
}
It just seems like this is getting the SPListItem by multiple ways, when it is passed in in the properties object... Same for the Website.. So, I guess my question is since they end up just getting the List item by the properties anyways through the list, is there really any reason to go through all the other checks/methods to just throw the value away in the end?
The difference is that it's not getting the list item using the current user's credentials; it's grabbing it using the system account's credentials.
The system account may have permissions surrounding the list item that the current user does not.
That said, there are most certainly easier ways of getting the list items, and there's no reason to get it several times like that, even if getting it once may be appropriate.

InvokeOperation C# and Silverlight

Can anyone help with the following code?
I'm trying to pass value from server to client via RIA Silverlight, but keep getting NullReferenceException.
I have removed all other attempts that I have tried and have just posted last attempt.
Server-side Code
namespace Web.UI.SilverlightDomainServices
{
// Implements application logic using the SilverlightDBEntities context.
// TODO: Add your application logic to these methods or in additional methods.
// TODO: Wire up authentication (Windows/ASP.NET Forms) and uncomment the following to disable anonymous access
// Also consider adding roles to restrict access as appropriate.
// [RequiresAuthentication]
[EnableClientAccess()]
public class VideoAdvertDomainService : LinqToEntitiesDomainService<SilverlightDBEntities>
{
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'at_AdvertVideoAdvertisement' query.
string strMonthYear = DateTime.Now.ToString("MMMM-yyyy");
[Invoke]
public List<string> GetMediaURLBasedOnMonthYear(string strMonthYear)
{
return (from p in this.ObjectContext.at_AdvertVideoAdvertisement
where p.AdvertMediaMonthYear == strMonthYear
select p.AdvertMediaURL).ToList();
}
public IQueryable<at_AdvertVideoAdvertisement> GetAt_AdvertVideoAdvertisement()
{
return this.ObjectContext.at_AdvertVideoAdvertisement;
}
}
}
Client-side Code
namespace Web.Silverlight
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private VideoAdvertDomainContext ctx = new VideoAdvertDomainContext();
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
string strMonthYear = DateTime.Now.ToString("MMMM-yyyy");
VideoAdvertDomainContext DomainContext = new VideoAdvertDomainContext();
InvokeOperation iv = DomainContext.GetMediaURLBasedOnMonthYear("September-2012");
iv.Value.ToString();
PlaylistItem item = new PlaylistItem();
item.MediaSource = new Uri(iv.Value.ToString());
item.DeliveryMethod = Microsoft.SilverlightMediaFramework.Plugins.Primitives.DeliveryMethods.AdaptiveStreaming;
MP.Playlist.Add(item);
}
}
}
Without seeing the stack trace from the exception, I have to guess.
Possibility 1
It could be that ObjectContext is null and therefore, this line will throw the exception you are getting.
return (from p in this.ObjectContext.at_AdvertVideoAdvertisement
where p.AdvertMediaMonthYear == strMonthYear
select p.AdvertMediaURL).ToList();
Possibility 2
Is there a chance that the contents of this.ObjectContext.at_AdvertVideoAdvertisement are null?
If so, p could be null, which would cause the query to throw the exception.
Possibility 3
I suspect the offending line is:
iv.Value.ToString();
This line does nothing, but you also repeat this a couple of lines later in a useful context, so perhaps the first declaration is a mistake. However, this assumes that the InvokeOperation value returned by VideoAdvertDomainContext.GetMediaURLBasedOnMonthYear is not null and that its Value property is not null. This may not be the case.
Recommendation
I recommend placing a breakpoint on those lines and seeing what the variables look like in the debugger to track down the null reference. From there, you can start to work out why it is null and either make it so that it isn't, or fix your code so that it copes appropriately with null references.

Categories