SharePoint Backup Tool for Custom Lists - powershell

I have a SharePoint 2013 document library with three custom lists.
Once a day I would like to backup the custom lists as excel documents.
Is there an inbuilt functionality in SharePoint 2013 which can be configured as a recurring task?
Or should one use PowerShell or CSOM to write script or an application which is then run by a Windows Task?

you dont have any OOB features to do this, i had the same req and i wrote an Utility - PFB the code - this will give you an o/p in .csv file
class Program
{
private static DataTable dataTable;
private static SPList list;
static void Main(string[] args)
{
try
{
Console.WriteLine("Site Url: ");
string _siteUrl = Console.ReadLine();
if (!string.IsNullOrEmpty(_siteUrl))
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(_siteUrl))
{
if (site != null)
{
SPWeb web = site.RootWeb;
if (web != null)
{
// Export List code segment
Console.WriteLine("List Name:");
string _listName = Console.ReadLine();
if (!string.IsNullOrEmpty(_listName))
{
list = web.Lists[_listName];
if (list != null)
{
dataTable = new DataTable();
//Adds Columns to SpreadSheet
InitializeExcel(list, dataTable);
string _schemaXML = list.DefaultView.ViewFields.SchemaXml;
if (list.Items != null && list.ItemCount > 0)
{
foreach (SPListItem _item in list.Items)
{
DataRow dr = dataTable.NewRow();
foreach (DataColumn _column in dataTable.Columns)
{
if (dataTable.Columns[_column.ColumnName] != null && _item[_column.ColumnName] != null)
{
dr[_column.ColumnName] = _item[_column.ColumnName].ToString();
}
}
dataTable.Rows.Add(dr);
}
}
}
}
System.Web.UI.WebControls.DataGrid grid = new System.Web.UI.WebControls.DataGrid();
grid.HeaderStyle.Font.Bold = true;
grid.DataSource = dataTable;
grid.DataBind();
using (StreamWriter streamWriter = new StreamWriter("C:\\" + list.Title + ".xls", false, Encoding.UTF8))
{
using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(streamWriter))
{
grid.RenderControl(htmlTextWriter);
}
}
Console.WriteLine("File Created");
#endregion
}
}
}
});
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
Console.ReadLine();
}
// Create excel funution
public static void InitializeExcel(SPList list, DataTable _datatable)
{
if (list != null)
{
string _schemaXML = list.DefaultView.ViewFields.SchemaXml;
if (list.Items != null && list.ItemCount > 0)
{
foreach (SPListItem _item in list.Items)
{
foreach (SPField _itemField in _item.Fields)
{
if (_schemaXML.Contains(_itemField.InternalName))
{
if (_item[_itemField.InternalName] != null)
{
if (!_datatable.Columns.Contains(_itemField.InternalName))
{
_datatable.Columns.Add(new DataColumn(_itemField.StaticName, Type.GetType("System.String")));
}
}
}
}
}
}
}
}
}

Related

AutoCompleteTextField list does not always scroll to top?

The AutoCompleteTextField seems to work exactly as intended until I start backspacing in the TextField. I am not sure what the difference is, but if I type in something like "123 M" then I get values that start with "123 M". If I backspace and delete the M leaving "123 " in the field, the list changes, but it does not scroll to the top of the list.
I should note that everything works fine on the simulator and that I am experiencing this behavior when running a debug build on my iPhone.
EDIT: So this does not only seem to happen when backspacing. This image shows the results I have when typing in an address key by key. In any of the pictures where the list isn't viewable or is clipped, I am able to drag down on the list to get it to then display properly. I have not tried this on an Android device.
EDIT2:
public class CodenameOneTest {
private Form current;
private Resources theme;
private WaitingClass w;
private String[] properties = {"1 MAIN STREET", "123 E MAIN STREET", "12 EASTER ROAD", "24 MAIN STREET"};
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
}
public void start() {
if(current != null) {
current.show();
return;
}
Form form = new Form("AutoCompleteTextField");
form.setLayout(new BorderLayout());
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
protected boolean filter(String text) {
if(text.length() == 0) {
options.removeAll();
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
};
};
Container container = new Container(BoxLayout.y());
container.setScrollableY(true); // If you comment this out then the field works fine
container.add(ac);
form.addComponent(BorderLayout.CENTER, container);
form.show();
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
if(w != null) {
w.actionPerformed(null);
}
w = new WaitingClass();
String[] properties = getProperties(text);
if(Display.getInstance().isEdt()) {
Display.getInstance().invokeAndBlock(w);
}
else {
w.run();
}
return properties;
}
}
catch(Exception e) {
Log.e(e);
}
return null;
}
private String[] getProperties(String text) {
List<String> returnList = new ArrayList<>();
List<String> propertyList = Arrays.asList(properties);
for(String property : propertyList) {
if(property.startsWith(text)) {
returnList.add(property);
}
}
w.actionPerformed(null);
return returnList.toArray(new String[returnList.size()]);
}
class WaitingClass implements Runnable, ActionListener<ActionEvent> {
private boolean finishedWaiting;
public void run() {
while(!finishedWaiting) {
try {
Thread.sleep(30);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
finishedWaiting = true;
return;
}
}
public void stop() {
current = Display.getInstance().getCurrent();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
}
I used this code on an iPhone 4s:
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("AutoComplete", new BorderLayout());
if(apiKey == null) {
hi.add(new SpanLabel("This demo requires a valid google API key to be set in the constant apiKey, "
+ "you can get this key for the webservice (not the native key) by following the instructions here: "
+ "https://developers.google.com/places/web-service/get-api-key"));
hi.getToolbar().addCommandToRightBar("Get Key", null, e -> Display.getInstance().execute("https://developers.google.com/places/web-service/get-api-key"));
hi.show();
return;
}
Container box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
box.setScrollableY(true);
for(int iter = 0 ; iter < 30 ; iter++) {
box.add(createAutoComplete());
}
hi.add(BorderLayout.CENTER, box);
hi.show();
}
private AutoCompleteTextField createAutoComplete() {
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
#Override
protected boolean filter(String text) {
if(text.length() == 0) {
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
}
};
ac.setMinimumElementsShownInPopup(5);
return ac;
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
ConnectionRequest r = new ConnectionRequest();
r.setPost(false);
r.setUrl("https://maps.googleapis.com/maps/api/place/autocomplete/json");
r.addArgument("key", apiKey);
r.addArgument("input", text);
NetworkManager.getInstance().addToQueueAndWait(r);
Map<String,Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
String[] res = Result.fromContent(result).getAsStringArray("//description");
return res;
}
} catch(Exception err) {
Log.e(err);
}
return null;
}
I was able to create this issue but not the issue you describe.

Dynamic models Entity Framework

I'm currently working on a generic function for inserting data tables via entity framework. However, with my current solution I ended up with a ton of very repetitive code with only a few minor differences. I would like to simplify what I have and remove the need for large case statements based on my table names (I only included two cases in this example to save space).
Here is what I currently have:
public static void InsertByTable(IEnumerable<DataTable> chunkedTable, string tableName)
{
switch (tableName)
{
#region Parcel
case TaxDataConstant.Parcel:
Parallel.ForEach(
chunkedTable,
new ParallelOptions
{
MaxDegreeOfParallelism = Convert.ToInt32(ConfigurationManager.AppSettings["MaxThreads"])
},
chunk =>
{
Realty_Records_ProdEntities entities = null;
try
{
entities = new Realty_Records_ProdEntities();
entities.Configuration.AutoDetectChangesEnabled = false;
foreach (DataRow dr in chunk.Rows)
{
var parcelToInsert = new Parcel();
foreach (DataColumn c in dr.Table.Columns)
{
SetProperty(parcelToInsert, c.ColumnName, dr[c.ColumnName]);
}
entities.Parcels.Add(parcelToInsert);
}
entities.SaveChanges();
}
catch (Exception ex)
{
TaxDataError.AddTaxApplicationLog(
TaxDataConstant.CategoryError,
ex.Source,
ex.Message,
ex.StackTrace);
throw;
}
finally
{
entities?.Dispose();
}
});
break;
#endregion
#region Asmt
case TaxDataConstant.Asmt:
Parallel.ForEach(
chunkedTable,
new ParallelOptions
{
MaxDegreeOfParallelism = Convert.ToInt32(ConfigurationManager.AppSettings["MaxThreads"])
},
chunk =>
{
Realty_Records_ProdEntities entities = null;
try
{
entities = new Realty_Records_ProdEntities();
entities.Configuration.AutoDetectChangesEnabled = false;
foreach (DataRow dr in chunk.Rows)
{
var asmtToInsert = new Asmt();
foreach (DataColumn c in dr.Table.Columns)
{
SetProperty(asmtToInsert, c.ColumnName, dr[c.ColumnName]);
}
entities.Asmts.Add(asmtToInsert);
}
entities.SaveChanges();
}
catch (Exception ex)
{
TaxDataError.AddTaxApplicationLog(
TaxDataConstant.CategoryError,
ex.Source,
ex.Message,
ex.StackTrace);
throw;
}
finally
{
entities?.Dispose();
}
});
break;
#endregion
}
}
Is there any way I can make this table agnostic?
You can probably move the logic in the case statement to a helper extension method which is generic. something like this (untested) pseudo code:
public static class EntityAdder
{
public static void AddEntities<T>(this IEnumerable<DataTable> chunkedEntities, Action<Realty_Records_ProdEntities, T entity> addingFunction)
{
Parallel.ForEach(
chunkedTable,
new ParallelOptions
{
MaxDegreeOfParallelism = Convert.ToInt32(ConfigurationManager.AppSettings["MaxThreads"])
},
chunk =>
{
Realty_Records_ProdEntities entities = null;
try
{
entities = new Realty_Records_ProdEntities();
entities.Configuration.AutoDetectChangesEnabled = false;
foreach (DataRow dr in chunk.Rows)
{
var toInsert = new T();
foreach (DataColumn c in dr.Table.Columns)
{
SetProperty(parcelToInsert, c.ColumnName, dr[c.ColumnName]);
}
addingFunction(entities,toInsert);
}
entities.SaveChanges();
}
catch (Exception ex)
{
TaxDataError.AddTaxApplicationLog(
TaxDataConstant.CategoryError,
ex.Source,
ex.Message,
ex.StackTrace);
throw;
}
finally
{
entities?.Dispose();
}
});
}
}
this could then be used something like this:
public static void InsertByTable(IEnumerable<DataTable> chunkedTable, string tableName)
{
switch (tableName)
{
#region Parcel
case TaxDataConstant.Parcel:
chunkedTable.AddEntities((entities,newEntity)=> entities.Parcels.Add(newEntity))
break;
#endregion
#region Asmt
case TaxDataConstant.Asmt:
chunkedTable.AddEntities((entities,newEntity)=> entities.Asmts.Add(newEntity))
break;
#endregion
}
}
you might be able to automate the adding bit by finding the property on the class which is a list of the things you want to add and avoid passing the action in if you wanted.
Based on Sams response and some further research I was able to refactor out the case statement.
Here's my solution:
public static void InsertByTable(IEnumerable<DataTable> chunkedTable, Type type)
{
Parallel.ForEach(
chunkedTable,
new ParallelOptions
{
MaxDegreeOfParallelism = Convert.ToInt32(ConfigurationManager.AppSettings["MaxThreads"])
},
chunk =>
{
Realty_Records_ProdEntities entities = null;
try
{
entities = new Realty_Records_ProdEntities();
entities.Configuration.AutoDetectChangesEnabled = false;
var set = entities.Set(type);
foreach (DataRow dr in chunk.Rows)
{
var objectToInsert = Activator.CreateInstance(type);
foreach (DataColumn c in dr.Table.Columns)
{
SetProperty(objectToInsert, c.ColumnName, dr[c.ColumnName]);
}
set.Add(objectToInsert);
}
entities.SaveChanges();
}
catch (Exception ex)
{
TaxDataError.AddTaxApplicationLog(
TaxDataConstant.CategoryError,
ex.Source,
ex.Message,
ex.StackTrace);
throw;
}
finally
{
entities?.Dispose();
}
});
}

wicket download output stream

I want to download csv file , i take the response content and write to it , apprently wicket write after me and the content iam getting is the page html where it should be my csv
I have seen in the example the usage of throw new AbortException();
I am using version 6.7 , do you know if my version wicket has somthing instead of it ?
or rather I am doing somthing wrong ....
can you please help me ...
add(new Link<Void>("export") {
#Override
public void onClick() {
WebResponse response = (WebResponse) getResponse();
response.setAttachmentHeader("export.csv");
response.setContentType("text/csv");
OutputStream out = getResponse().getOutputStream();
try {
c.exportData(dataSource.getListForExport(), columns, out);
} catch (Exception ex) {
System.err.println(ex);
}
}
});
public <T> void exportData(List<T> list, List<IGridColumn<IDataSource<T>, T, String>> columns, OutputStream outputStream)
throws IOException {
long startTime = System.nanoTime();
PrintWriter out = new PrintWriter(new OutputStreamWriter(outputStream, Charset.forName(characterSet)));
try {
if (isExportHeadersEnabled()) {
boolean first = true;
for (IGridColumn<IDataSource<T>, T, String> col : columns) {
if (first) {
first = false;
} else {
out.print(delimiter);
System.out.println(delimiter);
}
if (col.getId().equals("checkBox")) {
continue;
}
out.print(quoteValue(col.getId()));
System.out.println(col.getId());
}
out.print("\r\n");
System.out.println("\r\n");
}
Iterator<? extends T> rowIterator = list.iterator();
while (rowIterator.hasNext()) {
T row = rowIterator.next();
boolean first = true;
for (IGridColumn<IDataSource<T>, T, String> col : columns) {
if (first) {
first = false;
} else {
out.print(delimiter);
System.out.println(delimiter);
}
if (col.getId().equals("checkBox")) {
continue;
}
Object o = (new PropertyModel<>(row, col.getId())).getObject();// ((AbstractColumn<T,
if (o != null) {
Class<?> c = o.getClass();
String s;
IConverter converter = Application.get().getConverterLocator().getConverter(c);
if (converter == null) {
s = o.toString();
} else {
s = converter.convertToString(o, Session.get().getLocale());
}
out.print(quoteValue(s));
System.out.println(quoteValue(s));
}
}
out.print("\r\n");
System.out.println("\r\n");
}
} catch (Exception ex) {
System.out.println(ex);
} finally {
System.out.println(out);
out.close();
// measure
System.out.print(System.nanoTime() - startTime);
}
}
The best way to do this is using dynamic resources. I'll suggest you to read chapter "Resource managment with Wicket" of this magnific free Wicket guide: https://code.google.com/p/wicket-guide/.
Here you have a similar example given in this guide in the section "Custom resources".
public class RSSProducerResource extends AbstractResource {
#Override
protected ResourceResponse newResourceResponse(Attributes attributes) {
ResourceResponse resourceResponse = new ResourceResponse();
resourceResponse.setContentType("text/xml");
resourceResponse.setTextEncoding("utf-8");
resourceResponse.setWriteCallback(new WriteCallback()
{
#Override
public void writeData(Attributes attributes) throws IOException
{
OutputStream outputStream = attributes.getResponse().getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
SyndFeedOutput output = new SyndFeedOutput();
try {
output.output(getFeed(), writer);
} catch (FeedException e) {
throw new WicketRuntimeException("Problems writing feed to response...");
}
}
});
return resourceResponse;
}
// method getFeed()...
}
And then you need to add the link in the desired page or component:
add(new ResourceLink("rssLink", new RSSProducerResource()));

filtering datagrid using combobox

I had created a datagridview like this
public void gridviewsetup()
{
tbl_Aplication.Columns.Add("1", "Empid");
tbl_Aplication.Columns.Add("2", "Emp no");
tbl_Aplication.Columns.Add("3", "Emp Name");
tbl_Aplication.Columns.Add("4", "Department ");
tbl_Aplication.Columns.Add("5", "Designation");
tbl_Aplication.Columns.Add("6", "Shift");
tbl_Aplication.Columns.Add("7", "Start Time");
tbl_Aplication.Columns.Add("8", "End Time");
tbl_Aplication.Columns.Add("9", "OT");
tbl_Aplication.Columns.Add("10", "Reversed Swipe Out");
tbl_Aplication.RowTemplate.Height = 18;
}
and i had populated a data table to fill the data dgridview
public void filldatagrid()
{
if (cmb_dept.Text.Trim() != "")
{
Datatable employedata = empreg.getallemployeeshiftdetails(int.Parse(cmb_dept.SelectedValue.ToString()), Program.LOCTNPK);
tbl_Aplication.Rows.Clear();
tbl_Aplication.DataSource = null;
for (int i = 0; i < employedata.Rows.Count; i++)
{
tbl_Aplication.Rows.Add();
tbl_Aplication.Rows[i].Cells[1].Value = employedata.Rows[i][0];
tbl_Aplication.Rows[i].Cells[2].Value = employedata.Rows[i][1];
tbl_Aplication.Rows[i].Cells[3].Value = employedata.Rows[i][2];
tbl_Aplication.Rows[i].Cells[4].Value = employedata.Rows[i][3];
tbl_Aplication.Rows[i].Cells[5].Value = employedata.Rows[i][4];
tbl_Aplication.Rows[i].Cells[6].Value = employedata.Rows[i][5];
tbl_Aplication.Rows[i].Cells[7].Value = employedata.Rows[i][6];
tbl_Aplication.Rows[i].Cells[8].Value = employedata.Rows[i][7];
tbl_Aplication.Rows[i].Cells[9].Value = 0;
tbl_Aplication.Rows[i].Cells[10].Value = employedata.Rows[i][7];
}
}
}
now i want to filter data in the datagrid with the designation selected in the combobox without going back to database ,I did it like this but it shows error
private void cmb_designation_SelectedIndexChanged(object sender, EventArgs e)
{
if (desgflag != 0)
{
if (cmb_dept.SelectedValue!=null )
{
// tbl_Aplication.DataSource = employedata;
((DataTable)tbl_Aplication.DataSource).DefaultView.RowFilter = " designationnName like '%" + cmb_dept.Text.Trim() + "%' ";
}
}
}
I had done it
private void cmb_department_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
if (cmb_department.Text.Trim() == "" || cmb_department.Text.Trim() == null)
{
tbl_DestinationData.DataSource = dt;
}
else
{
((DataTable)tbl_DestinationData.DataSource).DefaultView.RowFilter = " Dept like '%" + cmb_department.Text.Trim() + "%' ";
}
}
catch (Exception )
{
throw;
}
}

Prevent sending email and show message via plug-in

I am writing crm2011 plugin in "Email" entity with "Send" Message of Pre_operation. What i want to do is when i click "Send" button in email entity, I do the necessary checking before send. If the checking is not correct, I want to prevent and stop the sending email and show "the alert message" and stop the second plugin(this plugin send email and create the associated entity to convert "Case"). Please give me some suggestion for that plugin?
Should i use pre-Validation stage or Pre_operation state? And how can I return false to stop plugin.
public void Execute(IServiceProvider serviceProvider)
{
try
{
string message = null;
_serviceProvider = serviceProvider;
_context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
_serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
_currentUser = _context.UserId;
message = _context.MessageName.ToLower();
if (message == "send")
{
if (_context.InputParameters != null && _context.InputParameters.Contains("EmailId"))
{
object objEmailId = _context.InputParameters["EmailId"];
if (objEmailId != null)
{
_emailId = new Guid(objEmailId.ToString());
FindEmailInfo();
if (_email != null)
{
if (_email.Attributes.Contains("description") && _email.Attributes["description"] != null)//Email descritpion is not null
{
string emaildescription = StripHTML();
//Find KB Article prefix no in system config entity
serviceguideprefix = "ServiceGuidesPrefix";
QueryByAttribute query = new QueryByAttribute("ppp_systemconfig");
query.ColumnSet = new ColumnSet(true);
query.AddAttributeValue(sysconfig_name, serviceguideprefix);
EntityCollection sysconfig = _service.RetrieveMultiple(query);
if (sysconfig.Entities.Count > 0)
{
Entity e = sysconfig.Entities[0];
if (e.Attributes.Contains("ppp_value"))
{
ppp_value = e.Attributes["ppp_value"].ToString();
}
}
if (ppp_value != null && ppp_value != string.Empty)
{
//var matches = Regex.Matches(emaildescription, #"KBA-\d*-\w*").Cast<Match>().ToArray();
var matches = Regex.Matches(emaildescription, ppp_value + #"-\d*-\w*").Cast<Match>().ToArray();
//ReadKBNo(emaildescription);
foreach (Match kbnumber in matches)
{
EntityCollection kbarticlecol = FindKBArticleIds(kbnumber.ToString());
if (kbarticlecol.Entities.Count > 0)
{
Entity kbariticle = kbarticlecol.Entities[0];
if (kbariticle.Attributes.Contains("mom_internalkm"))
{
bool internalserviceguide = (bool)kbariticle.Attributes["mom_internalkm"];
if (internalserviceguide) found = true;
else found = false;
}
else found = false;
}
}
}
if (found)
{
//-----
}
}
}
}
}
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message, ex);
}
}
Well stopping the plugin is dead easy you just throw InvalidPluginException, the message you give it will be shown to the user in a alert window. You will have to do this on the pre of the send. In this case I don't think it will matter if its pre-validation or pre-operation.
Edit:
Yes, you should throw an InvalidPluginException even if no exception has happened in code. I accept this isnt what we would normally do, but its the way its meant to work. Msdn has more details: http://msdn.microsoft.com/en-us/library/gg334685.aspx
So for example the code would look like:
public void Execute(IServiceProvider serviceProvider)
{
try
{
//This is where we validate the email send
if(emailIsOkay)
{
//Do something
}
else if(emailIsNotOkay)
{
//Throw and exception that will stop the plugin and the message will be shown to the user (if its synchronous)
throw new InvalidPluginExecutionException("Hello user, your email is not correct!!");
}
}
catch (InvalidPluginExecutionException invalid)
{
//We dont to catch exception for InvalidPluginExecution, so just throw them on
throw;
}
catch (Exception ex)
{
//This exception catches if something goes wrong in the code, or some other process.
throw new InvalidPluginExecutionException(ex.Message, ex);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Crm;
using Microsoft.Xrm.Sdk;
using System.ServiceModel;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
using System.Text.RegularExpressions;
using System.Xml.Linq;
namespace SendEmail
{
public class Email : IPlugin
{
public void Execute(IServiceProvider serviceprovider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
if (!(context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity))
return;
//entity
Entity ent = (Entity)context.InputParameters["Target"];
if (ent.LogicalName != "entityName")//EntityName
throw new InvalidPluginExecutionException("Not a Service Request record! ");
//service
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService _service = serviceFactory.CreateOrganizationService(context.UserId);
string Email="";
if (ent.Contains("emailidfiled"))
Email = (string)ent["emailidfiled"];
#region email template
QueryExpression query = new QueryExpression()
{
EntityName = "template",
Criteria = new FilterExpression(LogicalOperator.And),
ColumnSet = new ColumnSet(true)
};
query.Criteria.AddCondition("title", ConditionOperator.Equal, "templateName");
EntityCollection _coll = _service.RetrieveMultiple(query);
if (_coll.Entities.Count == 0)
throw new InvalidPluginExecutionException("Unable to find the template!");
if (_coll.Entities.Count > 1)
throw new InvalidPluginExecutionException("More than one template found!");
var subjectTemplate = "";
if (_coll[0].Contains("subject"))
{
subjectTemplate = GetDataFromXml(_coll[0]["subject"].ToString(), "match");
}
var bodyTemplate = "";
if (_coll[0].Contains("body"))
{
bodyTemplate = GetDataFromXml(_coll[0]["body"].ToString(), "match");
}
#endregion
#region email prep
Entity email = new Entity("email");
Entity entTo = new Entity("activityparty");
entTo["addressused"] =Email;
Entity entFrom = new Entity("activityparty");
entFrom["partyid"] = "admin#admin.com";
email["to"] = new Entity[] { entTo };
email["from"] = new Entity[] { entFrom };
email["regardingobjectid"] = new EntityReference(ent.LogicalName, ent.Id);
email["subject"] = subjectTemplate;
email["description"] = bodyTemplate;
#endregion
#region email creation & sending
try
{
var emailid = _service.Create(email);
SendEmailRequest req = new SendEmailRequest();
req.EmailId = emailid;
req.IssueSend = true;
GetTrackingTokenEmailRequest wod_GetTrackingTokenEmailRequest = new GetTrackingTokenEmailRequest();
GetTrackingTokenEmailResponse wod_GetTrackingTokenEmailResponse = (GetTrackingTokenEmailResponse)
_service.Execute(wod_GetTrackingTokenEmailRequest);
req.TrackingToken = wod_GetTrackingTokenEmailResponse.TrackingToken;
_service.Execute(req);
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException("Email can't be saved / sent." + Environment.NewLine + "Details: " + ex.Message);
}
#endregion
}
private static string GetDataFromXml(string value, string attributeName)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
XDocument document = XDocument.Parse(value);
// get the Element with the attribute name specified
XElement element = document.Descendants().Where(ele => ele.Attributes().Any(attr => attr.Name == attributeName)).FirstOrDefault();
return element == null ? string.Empty : element.Value;
}
}
}