Upload CSV to BigQuery in C# - c#-4.0

Basically what I want to do is to submit a job to BigQuery (Asynchronously), check job status after and print out corresponding status info or error info. I created a frame as below. But I need help on:
GoogleApiException: Not Found Job exception when "BigQueryService.Jobs.Get(jobReference.ProjectId, jobReference.JobId).Execute()" was called. My gut is that the job wasn't submit correctly, but I don't know how to do it correctly.
How should I handle GoogleApiExceptions?
Firt step: create a Job (uploading CSV file into BigQuery), return the JobReference
TableReference DestTable = new TableReference();
DestTable.ProjectId = project;
DestTable.DatasetId = dataset;
DestTable.TableId = tableId;
Job Job = new Job();
JobConfiguration Config = new JobConfiguration();
JobConfigurationLoad ConfigLoad = new JobConfigurationLoad();
ConfigLoad.Schema = schema;
ConfigLoad.DestinationTable = DestTable;
ConfigLoad.Encoding = "ISO-8859-1";
ConfigLoad.CreateDisposition = "CREATE_IF_NEEDED";
ConfigLoad.WriteDisposition = createDisposition;
ConfigLoad.FieldDelimiter = delimiter.ToString();
ConfigLoad.AllowJaggedRows = true;
Config.Load = ConfigLoad;
Job.Configuration = Config;
//set job reference (mainly job id)
JobReference JobRef = new JobReference();
JobRef.JobId = GenerateJobID("Upload");
JobRef.ProjectId = project;
Job.JobReference = JobRef;
using(FileStream fileStream = new FileStream(filePath,FileMode.Open)){
var JobInfo = BigQueryService.Jobs.Insert(Job,project,fileStream,"text/csv");//application/octet-stream
JobInfo.UploadAsync();
Console.WriteLine(JobInfo.GetProgress().Status.ToString());
}
return JobRef;
Then, Pull Job status using projectId and jobId in the returned JobReference from the first step:
while (true)
{
pollJob = BigQueryService.Jobs.Get(jobReference.ProjectId, jobReference.JobId).Execute();
i = 0;
Console.WriteLine("Job status" + jobReference.JobId + ": " + pollJob.Status.State);
if (pollJob.Status.State.Equals("DONE"))
{
return pollJob;
}
// Pause execution for pauseSeconds before polling job status again,
// to reduce unnecessary calls to the BigQuery API and lower overall
// application bandwidth.
Thread.Sleep(pauseSeconds * 1000);
}

There's hardly any useful sample code out there showing how to upload a local CSV file to Bigquery table. I eventually get something to work. It might not be the best solution, but it at least works. It's open to any improvement.
private JobReference JobUpload(string project, string dataset, string tableId, string filePath, TableSchema schema, string createDisposition, char delimiter)
{
TableReference DestTable = new TableReference();
DestTable.ProjectId = project;
DestTable.DatasetId = dataset;
DestTable.TableId = tableId;
Job Job = new Job();
JobConfiguration Config = new JobConfiguration();
JobConfigurationLoad ConfigLoad = new JobConfigurationLoad();
ConfigLoad.Schema = schema;
ConfigLoad.DestinationTable = DestTable;
ConfigLoad.Encoding = "ISO-8859-1";
ConfigLoad.CreateDisposition = "CREATE_IF_NEEDED";
ConfigLoad.WriteDisposition = createDisposition;
ConfigLoad.FieldDelimiter = delimiter.ToString();
ConfigLoad.AllowJaggedRows = true;
ConfigLoad.SourceFormat = "CSV";
Config.Load = ConfigLoad;
Job.Configuration = Config;
//set job reference (mainly job id)
JobReference JobRef = new JobReference();
JobRef.JobId = GenerateJobID("Upload");
JobRef.ProjectId = project;
Job.JobReference = JobRef;
using(FileStream fileStream = new FileStream(filePath,FileMode.Open)){
JobsResource.InsertMediaUpload InsertMediaUpload = new JobsResource.InsertMediaUpload(BigQueryService,Job,Job.JobReference.ProjectId,fileStream,"application/octet-stream");
var JobInfo = InsertMediaUpload.UploadAsync();
Console.WriteLine(JobInfo.Status);
while (!JobInfo.IsCompleted)
{
//wait for the job to be activated and run
Console.WriteLine(JobInfo.Status);
}
}
return JobRef;
}
After this, you can actually use the returned JobRef to pull job status, almost the same as we do with Java API:
while(true)
{
PollJob = BigQueryService.Jobs.Get(jobReference.ProjectId, jobReference.JobId).Execute();
Console.WriteLine("Job status" + jobReference.JobId + ": " + PollJob.Status.State);
if (PollJob.Status.State.Equals("DONE"))
{
return PollJob;
}
}

Related

Apache Beam Metrics Counter giving incorrect count using SparkRunner

I am having source and target csv files with 10 million records with 250 columns.
I am running an apache beam pipeline which joins all columns from source and target file.
When, I run this on spark cluster the pipeline executes correctly with no exceptions but,
The join beam metrics counter returns double count when the following spark property is used.
-- executor-memory "2g"
But, When I increase the excutor-memory to 11g then it returns the correct count.
I have tried following example,
Pipeline pipeline = Pipeline.create(options);
final TupleTag<String> eventInfoTag = new TupleTag<>();
final TupleTag<String> countryInfoTag = new TupleTag<>();
PCollection<KV<String, String>> eventInfo =
eventsTable.apply(ParDo.of(new ExtractEventDataFn()));
PCollection<KV<String, String>> countryInfo =
countryCodes.apply(ParDo.of(new ExtractCountryInfoFn()));
PCollection<KV<String, CoGbkResult>> kvpCollection =
KeyedPCollectionTuple.of(eventInfoTag, eventInfo)
.and(countryInfoTag, countryInfo)
.apply(CoGroupByKey.create());
PCollection<KV<String, String>> finalResultCollection =
kvpCollection.apply(
"Process",
ParDo.of(
new DoFn<KV<String, CoGbkResult>, KV<String, String>>() {
#ProcessElement
public void processElement(ProcessContext c) {
KV<String, CoGbkResult> e = c.element();
String countryCode = e.getKey();
String countryName = "none";
countryName = e.getValue().getOnly(countryInfoTag);
for (String eventInfo : c.element().getValue().getAll(eventInfoTag)) {
Metrics.counter("count", "errorcount").inc();
c.output(
KV.of(
countryCode,
"Country name: " + countryName + ", Event info: " + eventInfo));
}
}
}));
final PipelineResult result = pipeline.run();
MetricQueryResults metrics =
result
.metrics()
.queryMetrics(
MetricsFilter.builder()
.addNameFilter(MetricNameFilter.inNamespace("count"))
.build());
Iterable<MetricResult<Long>> counters = metrics.getCounters();
for (MetricResult<Long> counter : counters) {
System.out.println("Hi >> "+counter.getName().getName() + " : " + counter.getAttempted() + " " + counter.getCommittedOrNull());
}
I need help with this.
Thank you
public static void main(String[] args) {
Configuration hadoopConf = new Configuration();
hadoopConf.set("fs.defaultFS", args[13]);
hadoopConf.set("fs.hdfs.impl", org.apache.hadoop.hdfs.DistributedFileSystem.class.getName());
hadoopConf.set("fs.file.impl",org.apache.hadoop.fs.LocalFileSystem.class.getName());
final TupleTag<Row> sourceDataInfoTag = new TupleTag<Row>(){};
final TupleTag<Row> targetDataInfoTag = new TupleTag<Row>(){};
HadoopFileSystemOptions options = PipelineOptionsFactory.as(HadoopFileSystemOptions.class);
options.setRunner(SparkRunner.class);
options.setHdfsConfiguration(Collections.singletonList(hadoopConf));
Pipeline pipeline = Pipeline.create(options);
PCollection<String> sourceData = pipeline.apply(TextIO.read().from(args[14]).withDelimiter("\n".getBytes()));
PCollection<KV<Row, Row>> sourceDataRows = sourceData.apply(ParDo.of(new ExtractFunction()));
PCollection<String> targetData = pipeline.apply(TextIO.read().from(args[23]).withDelimiter("\n".getBytes()));
PCollection<KV<Row, Row>> targetDataRows = targetData.apply(ParDo.of(new ExtractFunction()));
PCollection<KV<Row, CoGbkResult>> kvpCollection = KeyedPCollectionTuple
.of(sourceDataInfoTag, sourceDataRows.setCoder(KvCoder.of(RowCoder.of(SOURCE_JOIN_RECORD_TYPE),RowCoder.of(SOURCE_RECORD_TYPE))))
.and(targetDataInfoTag, targetDataRows.setCoder(KvCoder.of(RowCoder.of(TARGET_JOIN_RECORD_TYPE),RowCoder.of(TARGET_RECORD_TYPE))))
.apply(CoGroupByKey.<Row>create());
PCollection<GenericRecord> finalResultCollections = kvpCollection.apply("process",ParDo.of(new DoFn<KV<Row, CoGbkResult>, GenericRecord>() {
#ProcessElement
public void processElement(ProcessContext context) {
KV<Row, CoGbkResult> element = context.element();
Iterator<Row> srcIter = element.getValue().getAll(sourceDataInfoTag).iterator();
Iterator<Row> trgIter = element.getValue().getAll(targetDataInfoTag).iterator();
Metrics.counter("count", "count").inc();
GenericRecordBuilder builder = new GenericRecordBuilder(SCHEMA);
boolean done = false;
boolean captureError = false;
while (!done)
{
// Some iterator data here.
.
.
builder.set(colName, data);
if(captureError){
GenericRecord record = builder.build();
context.output(record);
}
}
}
})).setCoder(AvroCoder.of(GenericRecord.class, SCHEMA));
finalResultCollections.apply("writeText",FileIO.<GenericRecord>write()
.via(ParquetIO.sink(SCHEMA))
.withSuffix(".parquet")
.withPrefix("part")
.to("hdfs://temp/"));
final PipelineResult result = pipeline.run();
State state = result.waitUntilFinish();
MetricQueryResults metrics =
result
.metrics()
.queryMetrics(
MetricsFilter.builder()
.addNameFilter(MetricNameFilter.inNamespace("count"))
.build());
Iterable<MetricResult<Long>> counters = metrics.getCounters();
for (MetricResult<Long> counter : counters) {
System.out.println("Count >> "+counter.getName().getName() + " : " + counter.getAttempted() + " " + counter.getCommittedOrNull());
}
}
In your code, when you do Metrics.counter("count", "errorcount") you define the counter. But it is defined in a loop which is also in sort of a loop (processElement). You should define your counter as a field in the DoFn. Don't worry the DoFn is reused for processing the bundle. Such as: private final Counter counter = Metrics.counter(MyClass.class, COUNTER_NAME);
Also you showed only part of the code but I don't see done boolean set to true. But that is just out of curiosity.
And last but not least, you should try spark runner on master branch of Beam because there was a fix merged yesterday about metrics (metrics not reset when running multiple pipelines inside the same JVM). I don't know if it matches your use case but it's worth trying.

How to export (save) data in OpenFL (Haxe) via XML(?)

In AS3 I could write the following:
fileReference = new FileReference();
var xmlStage:XML = new XML(<STAGE/>);
var xmlObjects:XML = new XML(<OBJECTS/>);
var j:uint;
var scene:SomeScene = ((origin_ as SecurityButton).origin as SomeScene);
var object:SomeObject;
for (j = 0; j < scene.objectArray.length; ++j) {
object = scene.objectArray[j];
if (1 == object.saveToXML){
var item:String = "obj";
var o:XML = new XML(<{item}/>);
o.#x = scene.objectArray[j].x;
o.#y = scene.objectArray[j].y;
o.#n = scene.objectArray[j].name;
o.#g = scene.objectArray[j].band;
o.#f = scene.objectArray[j].frame;
o.#w = scene.objectArray[j].width;
o.#h = scene.objectArray[j].height;
o.#s = scene.objectArray[j].sprite;
o.#b = scene.objectArray[j].bodyType;
xmlObjects.appendChild(o);
//System.disposeXML(o);
}
}
xmlStage.appendChild(xmlObjects);
fileReference.save(xmlStage, "XML.xml");
//System.disposeXML(xmlObjects);
//System.disposeXML(xmlStage);
//fileReference = null;
Is there an equivalent way to do this in Haxe? (Target of interest: HTML5)
If not, what are my options?
(The exported results of this code in AS3 are shown in this link below)
https://pastebin.com/raw/5twiJ01B
You can use the Xml class to create xml (see example: https://try.haxe.org/#68cfF )
class Test {
static function main() {
var root = Xml.createElement('root');
var child = Xml.createElement('my-element');
child.set('attribute1', 'value1'); //add your own object's values
child.set('attribute2', 'value2'); //may be add a few more children
root.addChild(child);
//this could be a file write, or POST'ed to http, or socket
trace(root.toString()); // <root><my-element attribute1="value1" attribute2="value2"/></root>
}
}
The root.toString() in that example could be instead serialized to a file File, or indeed any other kind of output (like POSTing via http to somewhere).
You could use FileReference for flash target, and sys.io and File for supported targets:
var output = sys.io.File.write(path, true);
output.writeString(data);
output.flush();
output.close();

Converting Hand Written DI to Windsor Provided DI

For the past six or seven months I have been doing DI in some of my components as result they have grown to become little bit of complicated. In the past I have been creating Object graphs with hand written Factories. Since it is becoming unmanageable I am trying to move that code to Framework dependent DI(by code and not by some XML files). I am posting my Code as well as issues I am stuck with.
Here is my composition layer (it is big, so bear with me :) ):
IAgentFactory GetAgentFactory()
{
string errorMessage;
IDictionary<AgentType, ServiceParameters> agentFactoryPrerequisite = new Dictionary<AgentType, ServiceParameters>();
string restResponseHeaderStatus = MyConfigurationProject.GetConfigValue("RestResponseHeaderStatus", out errorMessage);
var service1Parameters = new ServiceParameters();
service1Parameters.BindingName = MyConfigurationProject.GetConfigValue("Service1WebHttpBindingConfiguration", out errorMessage).ToString();
service1Parameters.HeaderPassword = MyConfigurationProject.GetConfigValue("Service1HeaderPassword", out errorMessage).ToString();
service1Parameters.HeaderUserName = MyConfigurationProject.GetConfigValue("Service1HeaderUserName", out errorMessage).ToString();
service1Parameters.ResponseHeaderStatus = restResponseHeaderStatus;
service1Parameters.ServicePassword = MyConfigurationProject.GetConfigValue("Service1ServicePassword", out errorMessage).ToString();
service1Parameters.ServiceUrl = MyConfigurationProject.GetConfigValue("Service1URL", out errorMessage).ToString();
service1Parameters.ServiceUserName = MyConfigurationProject.GetConfigValue("Service1ServiceUserName", out errorMessage).ToString();
agentFactoryPrerequisite.Add(new KeyValuePair<AgentType, ServiceParameters>(AgentType.Service1, service1Parameters));
var agentFactory = new AgentFactory(agentFactoryPrerequisite);
return agentFactory;
}
protected DatalayerSettings GetDataLayerSettings()
{
var datalayerSettings = new DatalayerSettings();
datalayerSettings.ConnectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
datalayerSettings.MySchemaName = ConfigurationManager.AppSettings["MyDatabaseSchema"];
datalayerSettings.UpdatingUser = "Admin";
return datalayerSettings;
}
PostgersDAFactory GetPostGresDaFactory()
{
var datalayerSettings = GetDataLayerSettings();
return new PostgersDAFactory(datalayerSettings, "MyAssembly.PostgresDA", "MyDifferentAssembly.CommonDatalayer", "MyServiceLogPath");
}
public class PostgersDAFactory
{
readonly DatalayerSettings _datalayerSettings;
readonly string _assemblyName;
readonly string _logPath;
readonly string _mySecondAssemblyName;
public PostgersDAFactory(DatalayerSettings datalayerSettings, string assemblyName, string mySecondAssemblyName, string logPath)
{
_datalayerSettings = datalayerSettings;
_assemblyName = assemblyName;
_logPath = logPath;
_commonDaAssemblyName = commonDaAssemblyName;
}
public IDA1 GetDA1Instance()
{
var type1 = Type.GetType("MyAssembly.PostgresDA.ClassRealisingImplementation_For_DA1," + _assemblyName);
return (IDA1)Activator.CreateInstance(type1, _datalayerSettings, _logPath);
}
public IDA2 GetDA2Instance()
{
var type1 = Type.GetType("MyAssembly.PostgresDA.ClassRealisingImplementation_For_DA2," + _assemblyName);
return (IDA2)Activator.CreateInstance(type1, _datalayerSettings);
}
public IDA3 GetDA3Instance()
{
var type1 = Type.GetType("MyAssembly2.ClassRealisingImplementation_For_DA3," + _commonDaAssemblyName);
return (IDA3)Activator.CreateInstance(type1, _datalayerSettings);
}
}
public BaseFileHandler GetFileHandler(FileProvider fileprovider, MockedServiceCalculator mockedServicecalculator = null)
{
string errorMessage;
var postgresFactory = GetPostGresDaFactory();
var Da1Instance = postgresFactory.GetDA1Instance();
var fileSyncBusiness = new FileSyncBusiness(Da1Instance);
var interfaceConfiguratonParameters = fileSyncBusiness.GetInterfaceConfigurationParameters();
var servicePointDetailsSettings = new ServicePointDetailsSettings();
var nullDate = new DateTime(2099, 1, 1);
CommonValidations commonValidations;
if (mockedServicecalculator == null)
{
commonValidations = GetStubbedCommonValidations(nullDate);
}
else
{
commonValidations = GetCommonValidations_WithMockedServiceCalculator(nullDate, mockedServicecalculator);
}
switch (fileprovider)
{
case FileProvider.Type1:
var type1Adapter = new Type1Adaptor(false, nullDate);
servicePointDetailsSettings = GetUtiltaParameters(interfaceConfiguratonParameters);
return new Type1FileHandler(servicePointDetailsSettings, fileSyncBusiness, commonValidations, type1Adapter);
case FileProvider.Type2:
var type2Adapter = new Type2Adaptor(true, nullDate);
servicePointDetailsSettings.ApplicableParameters = MyApplicationCommonMethods.ConvertConfigurationTableToDictonary(interfaceConfiguratonParameters, "applicableintype2");
servicePointDetailsSettings.BadFileLocation = MyConfigurationProject.GetConfigValue("Type2BadFileLocation", out errorMessage);
servicePointDetailsSettings.DateFormat = MyConfigurationProject.GetConfigValue("Type2DateFormat", out errorMessage);
servicePointDetailsSettings.FailureFileLocation = MyConfigurationProject.GetConfigValue("Type2FailureFile", out errorMessage);
servicePointDetailsSettings.LogFileName = "Type2LogFile";
servicePointDetailsSettings.LogPath = MyConfigurationProject.GetConfigValue("Type2ErrorLog", out errorMessage);
servicePointDetailsSettings.MandatoryParameters = MyApplicationCommonMethods.GetDictonaryForMandatoryParameters(interfaceConfiguratonParameters, "applicableintype2", "mandatoryintype2");
servicePointDetailsSettings.SourceFileLocation = MyConfigurationProject.GetConfigValue("type2FileLocation", out errorMessage);
servicePointDetailsSettings.SuccessFileLocation = MyConfigurationProject.GetConfigValue("type2SuccessFile", out errorMessage);
servicePointDetailsSettings.TargetFileExtension = MyConfigurationProject.GetConfigValue("type2SupportedFileType", out errorMessage);
servicePointDetailsSettings.Type2RecordTag = MyConfigurationProject.GetConfigValue("MyApplicationtype2RecordTag", out errorMessage);
return new Type2FileHandler(servicePointDetailsSettings, fileSyncBusiness, commonValidations, type2Adapter);
default:
throw new NotImplementedException("FileProvider type: " + Convert.ToInt32(fileprovider) + " is not implemented");
}
}
}
While moving towards Windsor, I am facing several issues, as I have never used this product, it seems it is very complicated.
Issues:
How to pass parameters to object when they have parameterised
constructors?
I know there is a better way to write this "PostgersDAFactory"
class, but simply don't know.
There are some Factory methods Such as GetAgentFactory(), which are
dependent on some static method of other project, which in turn
gives me configuration values(I ahd to store them in the database),
another method GetDataLayerSettings is dependent on app config as
well as some static string.
I am likely to change parameter names in my classes in order to
promote readability, so how to turn on the logging for Windsor?
Finally another complicated method GetFileHandler, has some logic
(switch case).
I have tried going on there website but I found it totally difficult to digest information, there API is huge and learning curve seems to be mammoth.
Note: I had to change the variable names due to security reasons.

Subsonic 3 Saving into different databases

Using subsonic 3 I have a project with a bit of a weird scenario. I have a .net windows service that needs to connect to a master database which stores connections to other database servers and also a set of tables for processing automated SMS messages. Then I have identical databases on the other servers (the connection string table is empty on the other db's) that handle the messages for other applications.
So, subsonic can call to all of the DB's just fine using the connection string/provider name options.
public static List<SMSRequestWithResponseList> SMSRequestListGetAll(string applicationName)
{
string connStr = GetConnectionStringByApplicationName(applicationName);
List<SMSRequestWithResponseList> response = new List<SMSRequestWithResponseList>();
List<DAL.CDYNESMSRequest> lst = DAL.CDYNESMSRequest.All(connStr, providerName).ToList();
foreach (DAL.CDYNESMSRequest mitm in lst)
{
SMSRequestWithResponseList itm = new SMSRequestWithResponseList(mitm, mitm.CDYNESMSResponses.ToList(), string.Empty);
response.Add(itm);
}
return response;
}
The issue is saving...Insert seems to be working.
DAL.CDYNESMSRequest itm = new DAL.CDYNESMSRequest(connStr, providerName).;
itm.KeyCode = KeyCode;
itm.ApplicationName = ApplicationName;
itm.BatchTransaction = BatchTransaction;
itm.AssignedDID = GetParameter("AssignedDID");
itm.PhoneNumber = PhoneNumber;
itm.MessageDetail = MessageText;
itm.MessageCancelled = false;
itm.MessageQueued = false;
itm.MessageSent = false;
itm.IsImmediate = SendImmediate;
itm.InQueue = false;
itm.ScheduledDateTime = ScheduledDateTime;
itm.CreateDT = dt;
itm.ModifiedDT = dt;
itm.Save();
But it doesn't seem to want to update...
DAL.CDYNESMSRequest itm = DAL.CDYNESMSRequest.SingleOrDefault(x => x.RequestID == requestID, connStr, providerName);
if (itm != null)
{
itm.MessageID = messageGUID;
itm.MessageCancelled = messageCancelled;
itm.MessageQueued = messageQueued;
itm.ReferenceID = messageReferenceID;
itm.MessageSent = messageSent;
if (messageSentDT < new DateTime(1753, 1, 1, 0, 0, 0))
itm.MessageSentDT = null;
else
itm.MessageSentDT = messageSentDT;
itm.MessageSMSError = messageSMSError;
itm.ModifiedDT = dt;
itm.Save();
}
I'm calling using the connection string from the correct database but it doesn't update the record.
If I'm saving it incorrectly please let me know. I did try to create a new provider and set it on the save but it barked at me saying it already had an open connection.
Thanks!
Don't use ActiveRecord pattern, but the SimpleRepository which allows you to setup multiple repos and you can specify a connectionstring per repo.
// not sure if this is the right constructor or if it's providerName, connectionString
var repo1 = new SimpleRepository(connectionString1, providerName);
var repo2 = new SimpleRepository(connectionString2, providerName);
var item = repo1.Single<Product>(1);
if (repo2.Exists<Product>(x => x.Id == item.Id))
repo2.Update(item);
else
repo2.Add(item);

Mark an appointment as Scheduled in CRM 2011

I have a Silverlight application that creates an appointment but since it's not marked as "Scheduled" it will not show up in the Calendar. I am using the SOAP service for this, and here is some sample code that fires on a button click that creates an appointment but it does not show up in the Calendar:
TestCommand = new RelayCommand(() =>
{
var soapCtx = ServiceHelper.GetSingletonSoapService();
var activityId = Guid.NewGuid();
var appt = new Entity()
{
Id = activityId,
LogicalName = "appointment"
};
appt["activityid"] = activityId;
appt["scheduledstart"] = DateTime.Now.Date;
appt["scheduledend"] = DateTime.Now.Date.AddHours(1);
appt["description"] = "Test 1 2 3";
appt["subject"] = "Test Command Button Appointment";
appt["location"] = "Location 1 2 3";
soapCtx.BeginCreate(appt, ar =>
{
var response = soapCtx.EndCreate(ar);
var bookRequest = new OrganizationRequest();
bookRequest.RequestName = "Book";
bookRequest["Target"] = appt;
soapCtx.BeginExecute(bookRequest,
new AsyncCallback(OnBookRequestedCompleted), soapCtx);
}, null);
});
void OnBookRequestedCompleted(IAsyncResult ar)
{
var soapCtx = (IOrganizationService)ar.AsyncState;
var response = soapCtx.EndExecute(ar);
}
I keep getting "NotFound" exception in the OnBookRequestedCompleted method. Is there a different way of doing this?
Use Fiddler to debug your HTTP request/response and this will give you details about the 'Not Found' exception.
You should not be setting the ActivityId field it is returned by the BookRequest. if BookResponse.ValidationResult.ValidationSuccess == true, apptId = BookResponse.ValidationResult.ActivityId
You need to call SetStateRequest with the id returned by the BookRequest to set the state to Scheduled
For example:
SetStateRequest state = new SetStateRequest();
state.State = new OptionSetValue(3); // Scheduled
state.Status = new OptionSetValue(5); // Busy
state.EntityMoniker = new EntityReference("appointment", apptId);
SetStateResponse stateSet = (SetStateResponse)this.orgService.Execute(state);

Resources