샘플: 피드 알림을 사용하여 공동 작업
게시 날짜: 2017년 1월
적용 대상: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online
이 샘플 코드는 Microsoft Dynamics 365(온라인 및 온-프레미스)용입니다. Microsoft Dynamics CRM SDK 패키지를 다운로드합니다. 다운로드 패키지의 다음 위치에서 확인할 수 있습니다.
SampleCode\CS\BusinessDataModel\ActivityFeeds\WorkingWithActivityFeeds.cs
요구 사항
이 SDK에서 제공된 샘플 코드를 실행하기 위한 요구 사항에 대한 자세한 내용은 샘플 및 도우미 코드 사용을 참조하십시오.
보여 주기
이 샘플에서는 댓글 및 언급과 함께 게시물을 만드는 방법과 Microsoft Dynamics 365 레코드를 팔로우하는 방법을 보여 줍니다. 개인 및 레코드 담벼락의 정보를 검색하는 방법도 보여 줍니다.
예제
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
namespace Microsoft.Crm.Sdk.Samples
{
/// <summary>
/// Demonstrates how to work with the new Activity Feeds entities, including Post,
/// PostFollow, and PostComment.</summary>
/// <remarks>
/// At run-time, you will be given the option to delete all the
/// database records created by this program.</remarks>
public class WorkingWithActivityFeeds
{
#region Local Sample Types
private class InvalidSampleExecutionException : Exception
{
public InvalidSampleExecutionException(String message)
: base(message)
{
}
}
#endregion Local Sample Types
#region Class Level Members
private OrganizationServiceProxy _serviceProxy;
private ServiceContext _serviceContext;
private msdyn_PostConfig _originalLeadConfig;
private msdyn_PostConfig _originalSystemUserConfig;
private msdyn_PostConfig _systemuserConfig;
private msdyn_PostConfig _leadConfig;
private List<msdyn_PostRuleConfig> _postRuleConfigs =
new List<msdyn_PostRuleConfig>();
private Lead _lead1;
private Lead _lead2;
private Lead _lead3;
private PostFollow _follow1;
private PostFollow _follow2;
private PostFollow _follow3;
private List<EntityReference> _generatedEntities = new List<EntityReference>();
private Post _post1;
private Post _post2;
private Post _post3;
private Post _post4;
private Post _leadPost1;
#endregion Class Level Members
#region How To Sample Code
/// <summary>
/// This method first connects to the Organization service. Afterwards, activity
/// feeds are enabled, posts and comments are made to entity records and user
/// walls and auto post rules are demonstrated.
/// </summary>
/// <param name="serverConfig">Contains server connection information.</param>
/// <param name="promptForDelete">When True, the user will be prompted to delete all
/// created entities.</param>
public void Run(ServerConnection.Configuration serverConfig, bool promptForDelete)
{
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri,serverConfig.Credentials, serverConfig.DeviceCredentials))
{
// This statement is required to enable early-bound type support.
_serviceProxy.EnableProxyTypes();
_serviceContext = new ServiceContext(_serviceProxy);
try
{
ConfigureActivityFeeds();
PostToRecordWalls();
PostToPersonalWalls();
ShowRecordWalls();
DeleteRequiredRecords(promptForDelete);
}
catch (InvalidSampleExecutionException e)
{
Console.WriteLine(e.Message);
DeleteRequiredRecords(promptForDelete);
}
}
}
private void ConfigureActivityFeeds()
{
Console.WriteLine("== Configuring Activity Feeds ==");
// Get the original systemuser config in order to keep a copy for reverting
// after the sample has completed.
_originalSystemUserConfig =
(from c in _serviceContext.msdyn_PostConfigSet
where c.msdyn_EntityName == SystemUser.EntityLogicalName
select new msdyn_PostConfig
{
msdyn_PostConfigId = c.msdyn_PostConfigId,
msdyn_ConfigureWall = c.msdyn_ConfigureWall,
msdyn_EntityName = c.msdyn_EntityName
}).FirstOrDefault();
// Retrieve or Create an instance of msdyn_PostConfig to enable activity
// feeds for leads (or make sure they are already enabled).
// If a new msdyn_PostConfig record gets created, activity feeds for
// systemusers will be enabled automatically.
_leadConfig =
(from c in _serviceContext.msdyn_PostConfigSet
where c.msdyn_EntityName == Lead.EntityLogicalName
select new msdyn_PostConfig
{
msdyn_PostConfigId = c.msdyn_PostConfigId,
msdyn_EntityName = c.msdyn_EntityName,
msdyn_ConfigureWall = c.msdyn_ConfigureWall
}).FirstOrDefault();
if (_leadConfig == null)
{
// Create the configuration record for leads.
_leadConfig = new msdyn_PostConfig
{
msdyn_EntityName = Lead.EntityLogicalName,
msdyn_ConfigureWall = true
};
_serviceContext.AddObject(_leadConfig);
_serviceContext.SaveChanges();
Console.WriteLine(
" The lead activity feed wall configuration was created.");
}
else
{
// Store the original Lead Config so that we can revert changes later.
_originalLeadConfig = CloneRelevantConfiguration(_leadConfig);
if (!_leadConfig.msdyn_ConfigureWall.HasValue
|| !_leadConfig.msdyn_ConfigureWall.Value)
{
_leadConfig.msdyn_ConfigureWall = true;
_serviceContext.UpdateObject(_leadConfig);
_serviceContext.SaveChanges();
Console.WriteLine(
" The lead activity feed wall was enabled.");
}
}
// Get the original systemuser config in order to keep a copy for reverting
// after the sample has completed.
_systemuserConfig =
(from c in _serviceContext.msdyn_PostConfigSet
where c.msdyn_EntityName == SystemUser.EntityLogicalName
select new msdyn_PostConfig
{
msdyn_PostConfigId = c.msdyn_PostConfigId,
msdyn_ConfigureWall = c.msdyn_ConfigureWall,
msdyn_EntityName = c.msdyn_EntityName
}).FirstOrDefault();
// Ensure that the wall for systemuser is enabled if there is already a
// systemuser configuration defined.
if (_systemuserConfig != null &&
(!_systemuserConfig.msdyn_ConfigureWall.HasValue
|| !_systemuserConfig.msdyn_ConfigureWall.Value))
{
_systemuserConfig.msdyn_ConfigureWall = true;
_serviceContext.UpdateObject(_systemuserConfig);
_serviceContext.SaveChanges();
Console.WriteLine(" The systemuser activity feed wall was enabled.");
}
// Publish the lead and systemuser entities so that they will have record
// walls on their forms.
PublishSystemUserAndLead();
// Activate the auto post rule configurations. New Lead qualified should be
// activated automatically when the rule is generated by CRM.
var leadRules =
(from r in _serviceContext.msdyn_PostRuleConfigSet
where r.msdyn_RuleId == "LeadQualify.Yes.Rule"
|| r.msdyn_RuleId == "LeadCreate.Rule"
select r).ToList();
if (leadRules.Count() != 2)
{
throw new InvalidSampleExecutionException(
" One or both of the lead config rules do not exist. This can be fixed by deleting the lead post config.");
}
foreach (var configRule in leadRules)
{
_postRuleConfigs.Add(configRule);
ActivateRuleConfig(configRule);
}
}
private void PostToRecordWalls()
{
Console.WriteLine("\r\n== Working with Record Walls ==");
// Create the leads.
CreateRequiredRecords();
// Follow each of the leads.
_follow1 = new PostFollow
{
RegardingObjectId = _lead1.ToEntityReference()
};
_serviceContext.AddObject(_follow1);
_follow2 = new PostFollow
{
RegardingObjectId = _lead2.ToEntityReference()
};
_serviceContext.AddObject(_follow2);
_follow3 = new PostFollow
{
RegardingObjectId = _lead3.ToEntityReference()
};
_serviceContext.AddObject(_follow3);
_serviceContext.SaveChanges();
Console.WriteLine(" The 3 leads are now followed.");
// Create posts, mentions, and comments related to the leads.
// Create a post related to lead 1 with a mention and a comment.
_leadPost1 = new Post
{
RegardingObjectId = _lead1.ToEntityReference(),
Source = new OptionSetValue((int)PostSource.AutoPost),
// Include a mention in the post text.
Text = String.Format("This lead is similar to @[{0},{1},\"{2}\"]",
Lead.EntityTypeCode, _lead2.Id, _lead2.FullName)
};
_serviceContext.AddObject(_leadPost1);
_serviceContext.SaveChanges();
Console.WriteLine(" Post 1 has been created.");
// It isn't necessary to keep track of the comment because the comment will
// be deleted when its parent post is deleted.
var comment1 = new PostComment
{
PostId = _leadPost1.ToEntityReference(),
Text = "Sample comment 1"
};
_serviceContext.AddObject(comment1);
_serviceContext.SaveChanges();
Console.WriteLine(" Comment 1 has been created.");
// Create a post related to lead 2 with three comments.
var post2 = new Post
{
RegardingObjectId = _lead2.ToEntityReference(),
Source = new OptionSetValue((int)PostSource.ManualPost),
Text = "This lead was created for a sample."
};
_serviceContext.AddObject(post2);
_serviceContext.SaveChanges();
Console.WriteLine(" Post 2 has been created.");
var comment2 = new PostComment
{
PostId = post2.ToEntityReference(),
Text = "Sample comment 2"
};
var comment3 = new PostComment
{
PostId = post2.ToEntityReference(),
Text = "Sample comment 3"
};
var comment4 = new PostComment
{
PostId = post2.ToEntityReference(),
Text = "Sample comment 4"
};
_serviceContext.AddObject(comment2);
_serviceContext.AddObject(comment3);
_serviceContext.AddObject(comment4);
_serviceContext.SaveChanges();
Console.WriteLine(" Comments 2, 3, and 4 have been created.");
// Qualify some leads. Since there is an active post rule config for
// qualification of a lead, this should generate an auto post to the record
// wall of each lead that is qualified.
// Qualify lead 2.
var qualifyLead2Request = new QualifyLeadRequest
{
CreateAccount = true,
LeadId = _lead2.ToEntityReference(),
Status = new OptionSetValue((int)lead_statuscode.Qualified)
};
var qualifyLead2Response = (QualifyLeadResponse)_serviceProxy.Execute(
qualifyLead2Request);
// Store the generated Account to delete it later.
foreach (var entityRef in qualifyLead2Response.CreatedEntities)
{
_generatedEntities.Add(entityRef);
}
Console.WriteLine(" Lead 2 was qualified.");
// Qualify lead 3.
var qualifyLead3Request = new QualifyLeadRequest
{
CreateAccount = true,
LeadId = _lead3.ToEntityReference(),
Status = new OptionSetValue((int)lead_statuscode.Qualified)
};
var qualifyLead3Response = (QualifyLeadResponse)_serviceProxy.Execute(
qualifyLead3Request);
foreach (var entityRef in qualifyLead3Response.CreatedEntities)
{
_generatedEntities.Add(entityRef);
}
Console.WriteLine(" Lead 3 was qualified.");
}
private void PostToPersonalWalls()
{
Console.WriteLine("\r\n== Working with Personal Walls ==");
// Create manual (user) posts on a user's Personal wall.
var whoAmIRequest = new WhoAmIRequest();
var whoAmIResponse = (WhoAmIResponse)_serviceProxy.Execute(whoAmIRequest);
var currentUserRef = new EntityReference(
SystemUser.EntityLogicalName, whoAmIResponse.UserId);
// Create a post that mentions lead 1.
// The Regarding object should be set to the user whose wall the post should
// be posted to (we'll just use the current user).
_post1 = new Post
{
RegardingObjectId = currentUserRef,
Source = new OptionSetValue((int)PostSource.ManualPost),
Text = String.Format("I'd rather not pursue @[{0},{1},\"{2}\"]",
Lead.EntityTypeCode, _lead1.Id, _lead1.FullName)
};
_serviceContext.AddObject(_post1);
_serviceContext.SaveChanges();
Console.WriteLine(" Personal wall post 1 was created.");
// Create a related comment.
var comment1 = new PostComment
{
PostId = _post1.ToEntityReference(),
Text = "Personal wall comment 1."
};
_serviceContext.AddObject(comment1);
_serviceContext.SaveChanges();
Console.WriteLine(" Personal wall comment 1 was created.");
_post2 = new Post
{
RegardingObjectId = currentUserRef,
Source = new OptionSetValue((int)PostSource.AutoPost),
Text = "Personal wall post 2."
};
_serviceContext.AddObject(_post2);
_serviceContext.SaveChanges();
Console.WriteLine(" Personal wall post 2 was created.");
// Create a few related comments.
var comment2 = new PostComment
{
PostId = _post2.ToEntityReference(),
Text = "Personal wall comment 2."
};
var comment3 = new PostComment
{
PostId = _post2.ToEntityReference(),
Text = "Personal wall comment 3."
};
var comment4 = new PostComment
{
PostId = _post2.ToEntityReference(),
Text = "Personal wall comment 4."
};
var comment5 = new PostComment
{
PostId = _post2.ToEntityReference(),
Text = "Personal wall comment 5."
};
_serviceContext.AddObject(comment2);
_serviceContext.AddObject(comment3);
_serviceContext.AddObject(comment4);
_serviceContext.AddObject(comment5);
_serviceContext.SaveChanges();
Console.WriteLine(" Personal wall comments 2, 3, 4, and 5 were created.");
// Create a couple more posts just to show how paging works.
_post3 = new Post
{
RegardingObjectId = currentUserRef,
Source = new OptionSetValue((int)PostSource.ManualPost),
Text = "Personal wall post 3."
};
_post4 = new Post
{
RegardingObjectId = currentUserRef,
Source = new OptionSetValue((int)PostSource.AutoPost),
Text = "Personal wall post 4."
};
_serviceContext.AddObject(_post3);
_serviceContext.AddObject(_post4);
_serviceContext.SaveChanges();
Console.WriteLine(" Personal wall posts 3 and 4 were created.");
// Retrieve this user's personal wall.
// Retrieve the first page of posts.
DisplayPersonalWallPage(1);
// Retrieve the second page of posts.
DisplayPersonalWallPage(2);
// Sleep for a second so that the time of the newly created comment will
// clearly be later than the previously created posts/comments (otherwise
// Post 3 will not be escalated to the top of the wall).
Thread.Sleep(1000);
// Create a new comment on the last post, which will bring the post to the
// top.
var newPostComment = new PostComment
{
PostId = _post3.ToEntityReference(),
Text = "New comment to show that new comments affect post ordering."
};
_serviceContext.AddObject(newPostComment);
_serviceContext.SaveChanges();
Console.WriteLine("\r\n A new comment was created to show effects on post ordering.");
// Display the first page of the personal wall to showcase the change in
// ordering. Post 3 should be at the top.
DisplayPersonalWallPage(1);
// Show paging of comments.
// Retrieve comments 2 at a time, starting with page 1.
var commentsQuery = new QueryExpression(PostComment.EntityLogicalName)
{
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression(LogicalOperator.And),
PageInfo = new PagingInfo
{
Count = 2,
PageNumber = 1,
ReturnTotalRecordCount = true
}
};
commentsQuery.Criteria.AddCondition(
"postid", ConditionOperator.Equal, _post2.Id);
// Continue querying for comments until there are no further comments to
// be retrieved.
EntityCollection commentsResult;
do
{
commentsResult = _serviceProxy.RetrieveMultiple(commentsQuery);
// Display the comments that we retrieved.
Console.WriteLine("\r\n Comments for lead 2 page {0}",
commentsQuery.PageInfo.PageNumber);
foreach (PostComment comment in commentsResult.Entities)
{
DisplayComment(comment);
}
commentsQuery.PageInfo.PageNumber += 1;
}
while (commentsResult.MoreRecords);
}
private void ShowRecordWalls()
{
Console.WriteLine("\r\n== Showing Record Walls ==");
// Create a new post on one of the leads.
var newLeadPost = new Post
{
Source = new OptionSetValue((int)PostSource.AutoPost),
Text = "New lead post.",
RegardingObjectId = _lead2.ToEntityReference(),
};
_serviceContext.AddObject(newLeadPost);
_serviceContext.SaveChanges();
Console.WriteLine(" The new lead 2 post has been created.");
DisplayRecordWall(_lead1);
DisplayRecordWall(_lead2);
DisplayRecordWall(_lead3);
}
private void DisplayRecordWall(Lead lead)
{
// Display the first page of the record wall.
var retrieveRecordWallReq = new RetrieveRecordWallRequest
{
Entity = lead.ToEntityReference(),
CommentsPerPost = 2,
PageSize = 10,
PageNumber = 1
};
var retrieveRecordWallRes =
(RetrieveRecordWallResponse)_serviceProxy.Execute(retrieveRecordWallReq);
Console.WriteLine("\r\n Posts for lead {0}:", lead.FullName);
foreach (Post post in retrieveRecordWallRes.EntityCollection.Entities)
{
DisplayPost(post);
}
}
private void DisplayPersonalWallPage(int pageNumber)
{
// Retrieve the page of posts. We'll only retrieve 5 at a time so that
// we will have more than one page.
var pageSize = 5;
var personalWallPageReq = new RetrievePersonalWallRequest
{
CommentsPerPost = 2,
PageNumber = pageNumber,
PageSize = pageSize
};
var personalWallPageRes =
(RetrievePersonalWallResponse)_serviceProxy.Execute(personalWallPageReq);
Console.WriteLine("\r\n Personal Wall Page {0} Posts:", pageNumber);
foreach (Post post in personalWallPageRes.EntityCollection.Entities)
{
DisplayPost(post);
}
}
private void DisplayPost(Post post)
{
Console.WriteLine(" Post, {0}, {1}, {2}: {3}",
post.CreatedBy.Name,
(PostType)post.Type.Value,
(PostSource)post.Source.Value,
Shorten(post.Text));
if (post.Post_Comments != null)
{
foreach (var comment in post.Post_Comments)
{
DisplayComment(comment);
}
}
}
private void DisplayComment(PostComment comment)
{
Console.WriteLine(" Comment, {0}: {1}",
comment.CreatedBy.Name, Shorten(comment.Text));
}
private String Shorten(String x)
{
return x.Length > 33 ? x.Substring(0, 30) + "..." : x;
}
private void CreateRequiredRecords()
{
// Create leads for relating activity feed records to. Since there is an
// active post rule config for creation of a new lead, creating the leads
// should add an auto post to the record wall for each of the leads.
_lead1 = new Lead
{
CompanyName = "A. Datum Corporation",
FirstName = "Henriette",
MiddleName = "Thaulow",
LastName = "Andersen",
Subject = "Activity Feeds Sample 1"
};
_serviceContext.AddObject(_lead1);
_lead2 = new Lead
{
CompanyName = "Adventure Works",
FirstName = "Mary",
MiddleName = "Kay",
LastName = "Andersen",
Subject = "Activity Feeds Sample 2"
};
_serviceContext.AddObject(_lead2);
_lead3 = new Lead
{
CompanyName = "Fabrikam, Inc.",
FirstName = "Andrew",
LastName = "Sullivan",
Subject = "Activity Feeds Sample 3"
};
_serviceContext.AddObject(_lead3);
_serviceContext.SaveChanges();
var columnSet = new ColumnSet(true);
_lead1 = (Lead)_serviceProxy.Retrieve(
Lead.EntityLogicalName, _lead1.Id, columnSet);
_lead2 = (Lead)_serviceProxy.Retrieve(
Lead.EntityLogicalName, _lead2.Id, columnSet);
_lead3 = (Lead)_serviceProxy.Retrieve(
Lead.EntityLogicalName, _lead3.Id, columnSet);
Console.WriteLine(" The leads have been created.");
}
private void ActivateRuleConfig(msdyn_PostRuleConfig qualifyLeadRule)
{
_serviceProxy.Execute(new SetStateRequest
{
EntityMoniker = qualifyLeadRule.ToEntityReference(),
State = new OptionSetValue((int)msdyn_PostRuleConfigState.Active),
Status = new OptionSetValue((int)msdyn_postruleconfig_statuscode.Active)
});
}
private msdyn_PostConfig CloneRelevantConfiguration(msdyn_PostConfig config)
{
return new msdyn_PostConfig
{
msdyn_ConfigureWall = config.msdyn_ConfigureWall,
msdyn_EntityName = config.msdyn_EntityName,
msdyn_PostConfigId = config.msdyn_PostConfigId
};
}
private void PublishSystemUserAndLead()
{
// The systemuser and lead entities must be published because otherwise the
// record walls on the respective forms will not update.
_serviceProxy.Execute(new PublishXmlRequest
{
ParameterXml = @"
<importexportxml>
<entities>
<entity>systemuser</entity>
<entity>lead</entity>
</entities>
</importexportxml>"
});
Console.WriteLine(" The systemuser and lead entities were published.");
}
private void DeleteRequiredRecords(bool prompt)
{
var toBeDeleted = true;
if (prompt)
{
// Ask the user if the created entities should be deleted.
Console.Write("\nDo you want these entity records deleted? (y/n) [y]: ");
String answer = Console.ReadLine();
if (answer.StartsWith("y") ||
answer.StartsWith("Y") ||
answer == String.Empty)
{
toBeDeleted = true;
}
else
{
toBeDeleted = false;
}
}
if (toBeDeleted)
{
// Handle reverting the configurations appropriately - delete them
// if they did not exist before. Otherwise update them to their
// original values. Lead must be reverted first since it must be deleted
// first if systemuser is to be deleted.
RevertPostConfig(_originalLeadConfig, _leadConfig);
RevertPostConfig(_originalSystemUserConfig, _systemuserConfig);
// Revert the form changes.
PublishSystemUserAndLead();
// Delete the leads.
DeleteFromContext(_lead1);
DeleteFromContext(_lead2);
DeleteFromContext(_lead3);
var saveResult = _serviceContext.SaveChanges();
Console.WriteLine(" The leads have been deleted.");
Console.WriteLine(" The post follow records were deleted with the leads.");
Console.WriteLine(" Posts that were related to leads were deleted with the leads.");
// Delete posts that aren't regarding entities that were deleted.
DeleteFromContext(_post1);
DeleteFromContext(_post2);
DeleteFromContext(_post3);
DeleteFromContext(_post4);
_serviceContext.SaveChanges();
Console.WriteLine(" Posts that weren't regarding deleted entities were deleted.");
// Delete the generated entities.
foreach (var entityRef in _generatedEntities)
{
_serviceProxy.Delete(entityRef.LogicalName, entityRef.Id);
}
Console.WriteLine(" All generated entities have been deleted.");
}
}
private void DeleteFromContext(Entity entity)
{
if (!_serviceContext.IsAttached(entity))
{
_serviceContext.Attach(entity);
}
_serviceContext.DeleteObject(entity);
_serviceContext.SaveChanges();
}
private void RevertPostConfig(msdyn_PostConfig originalConfig,
msdyn_PostConfig newConfig)
{
if (originalConfig != null)
{
// Revert the rule configs.
foreach (var rule in _postRuleConfigs.Where(
x => x.msdyn_PostConfigId.Id == newConfig.msdyn_PostConfigId))
{
// Set the state to the original value.
_serviceProxy.Execute(new SetStateRequest
{
EntityMoniker = rule.ToEntityReference(),
State = new OptionSetValue((int)rule.statecode),
Status = rule.statuscode
});
}
// Update the config to the values from the original config.
// Make sure the context is not tracking the new config and is tracking
// the original config.
if (!_serviceContext.IsAttached(originalConfig))
{
if (_serviceContext.IsAttached(newConfig))
{
_serviceContext.Detach(newConfig);
}
_serviceContext.Attach(originalConfig);
}
_serviceContext.UpdateObject(originalConfig);
_serviceContext.SaveChanges();
Console.WriteLine(
" The {0} activity feed configuration was reverted.",
originalConfig.msdyn_EntityName);
}
else
{
_serviceProxy.Delete(newConfig.LogicalName,
newConfig.Id);
Console.WriteLine(
" The {0} activity feed configuration was deleted.",
newConfig.msdyn_EntityName);
}
}
#endregion How To Sample Code
#region Main method
/// <summary>
/// Standard Main() method used by most SDK samples.
/// </summary>
/// <param name="args"></param>
static public void Main(string[] args)
{
try
{
// Obtain the target organization's Web address and client logon
// credentials from the user.
ServerConnection serverConnect = new ServerConnection();
ServerConnection.Configuration config = serverConnect.GetServerConfiguration();
var app = new WorkingWithActivityFeeds();
app.Run(config, true);
}
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp);
Console.WriteLine("Code: {0}", ex.Detail.ErrorCode);
Console.WriteLine("Message: {0}", ex.Detail.Message);
Console.WriteLine("Plugin Trace: {0}", ex.Detail.TraceText);
Console.WriteLine("Inner Fault: {0}",
null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
}
catch (System.TimeoutException ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Message: {0}", ex.Message);
Console.WriteLine("Stack Trace: {0}", ex.StackTrace);
Console.WriteLine("Inner Fault: {0}",
null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message);
}
catch (System.Exception ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine(ex.Message);
// Display the details of the inner exception.
if (ex.InnerException != null)
{
Console.WriteLine(ex.InnerException.Message);
FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe = ex.InnerException
as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>;
if (fe != null)
{
Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp);
Console.WriteLine("Code: {0}", fe.Detail.ErrorCode);
Console.WriteLine("Message: {0}", fe.Detail.Message);
Console.WriteLine("Plugin Trace: {0}", fe.Detail.TraceText);
Console.WriteLine("Inner Fault: {0}",
null == fe.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
}
}
}
// Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException,
// SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException.
finally
{
Console.WriteLine("Press <Enter> to exit.");
Console.ReadLine();
}
}
#endregion Main method
}
}
참고 항목
RetrievePersonalWallRequest
RetrieveRecordWallRequest
피드 알림 엔터티
피드 알림 소개
피드 알림 구성
Post 엔터티 메시지 및 메서드
PostComment(댓글) 엔터티 메시지 및 메서드
PostFollow(팔로우) 엔터티 메시지 및 메서드
Microsoft Dynamics 365
© 2017 Microsoft. All rights reserved. 저작권 정보